Use repeat of format for many variables on the same line - ruby

puts "%-30s%2s%3d%2s%3d%2s%3d%2s%3d%2s%3d" % [tn,ln,a,ln,b,ln,c,ln,d,ln,e]
This is Ruby, but many languages use this formatting. I have forgotten how to output several variables in the same format, without repeating the format in each case. Here, I want "%3d%2s" for 5 integers, each separated by a '|'

You could write the following.
def print_my_string(tn, ln, *ints)
fmt = "%-10s" + ("|#{"%2s" % ln}%3d" * ints.size) + "|"
puts fmt % [tn, *ints]
end
Then, for example,
print_my_string("hello", "ho", 2, 77, 453, 61, 999)
displays
hello |ho 2|ho 77|ho453|ho 61|ho999|
after having computed
fmt = "%-10s" + ("|#{"%2s" % ln}%3d" * ints.size) + "|"
#=> %-10s|ho%3d|ho%3d|ho%3d|ho%3d|ho%3d|"

Related

Ruby - How to subtract numbers of two files and save the result in one of them on a specified position?

I have 2 txt files with different strings and numbers in them splitted with ;
Now I need to subtract the
((number on position 2 in file1) - (number on position 25 in file2)) = result
Now I want to replace the (number on position 2 in file1) with the result.
I tried my code below but it only appends the number in the end of the file and its not the result of the calculation which got appended.
def calc
f1 = File.open("./file1.txt", File::RDWR)
f2 = File.open("./file2.txt", File::RDWR)
f1.flock(File::LOCK_EX)
f2.flock(File::LOCK_EX)
f1.each.zip(f2.each).each do |line, line2|
bg = line.split(";").compact.collect(&:strip)
bd = line2.split(";").compact.collect(&:strip)
n = bd[2].to_i - bg[25].to_i
f2.print bd[2] << n
#puts "#{n}" Only for testing
end
f1.flock(File::LOCK_UN)
f2.flock(File::LOCK_UN)
f1.close && f2.close
end
Use something like this:
lines1 = File.readlines('file1.txt').map(&:to_i)
lines2 = File.readlines('file2.txt').map(&:to_i)
result = lines1.zip(lines2).map do |value1, value2| value1 - value2 }
File.write('file1.txt', result.join(?\n))
This code load all files in memory, then calculate result and write it to first file.
FYI: If you want to use your code just save result to other file (i.e. result.txt) and at the end copy it to original file.

sorting a file of list created by python with write

I have a file created by python3 using:
of.write("{:<6f} {:<10f} {:<18f} {:<10f}\n"
.format((betah), test, (torque*13605.698066), (mom)))
The output file looks like:
$cat pout
15.0 47.13 0.0594315908872 0.933333333334
25.0 29.07 0.143582198404 0.96
20.0 35.95 0.220373446813 0.95
5.0 124.12 0.230837577743 0.800090803982
4.0 146.71 0.239706979471 0.750671150402
0.5 263.24 0.239785533064 0.163953413739
1.0 250.20 0.240498520899 0.313035285499
Now, I want to sort the list.
The expected output of sorting will be:
25.0 29.07 0.143582198404 0.96
20.0 35.95 0.220373446813 0.95
15.0 47.13 0.0594315908872 0.933333333334
5.0 124.12 0.230837577743 0.800090803982
4.0 146.71 0.239706979471 0.750671150402
1.0 250.20 0.240498520899 0.313035285499
0.5 263.24 0.239785533064 0.163953413739
I tried this and tuples example in this but they are yielding the output as
['0.500000 263.240000 0.239786 0.163953 \n', '15.000000 47.130000 0.059432 0.933333 \n', '1.000000 250.200000 0.240499 0.313035 \n', '25.000000 29.070000 0.143582 0.960000 \n', '20.000000 35.950000 0.220373 0.950000 \n', '4.000000 146.710000 0.239707 0.750671 \n', '5.000000 124.120000 0.230838 0.800091 \n']
Please, don't try to match the numbers of input and output, because both of them are truncated for brevity.
As an example for my own try for the sorting with help from 1 is like:
f = open("tmp", "r")
lines = [line for line in f if line.strip()]
print(lines)
f.close()
Kindly help me sorting the file properly.
The problem you've found is that the strings are sorted alphabetically instead of numerically. What you need to do is convert each item from a string to a float, sort the list of floats, and then output as a string again.
I've recreated your file here, so you can see that I'm reading directly from a file.
pout = [
"15.0 47.13 0.0594315908872 0.933333333334",
"25.0 29.07 0.143582198404 0.96 ",
"20.0 35.95 0.220373446813 0.95 ",
"5.0 124.12 0.230837577743 0.800090803982",
"4.0 146.71 0.239706979471 0.750671150402",
"0.5 263.24 0.239785533064 0.163953413739",
"1.0 250.20 0.240498520899 0.313035285499"]
with open('test.txt', 'w') as thefile:
for item in pout:
thefile.write(str("{}\n".format(item)))
# Read in the file, stripping each line
lines = [line.strip() for line in open('test.txt')]
acc = []
# Loop through the list of lines, splitting the numbers at the whitespace
for strings in lines:
words = strings.split()
# Convert each item to a float
words = [float(word) for word in words]
acc.append(words)
# Sort the new list, reversing because you want highest numbers first
lines = sorted(acc, reverse=True)
# Save it to the file.
with open('test.txt', 'w') as thefile:
for item in lines:
thefile.write("{:<6} {:<10} {:<18} {:<10}\n".format(item[0], item[1], item[2], item[3]))
Also note that I use with open('test.txt', 'w') as thefile: as it automatically handles all opening and closing. Much more memory-safe.

Join array of strings into 1 or more strings each within a certain char limit (+ prepend and append texts)

Let's say I have an array of Twitter account names:
string = %w[example1 example2 example3 example4 example5 example6 example7 example8 example9 example10 example11 example12 example13 example14 example15 example16 example17 example18 example19 example20]
And a prepend and append variable:
prepend = 'Check out these cool people: '
append = ' #FollowFriday'
How can I turn this into an array of as few strings as possible each with a maximum length of 140 characters, starting with the prepend text, ending with the append text, and in between the Twitter account names all starting with an #-sign and separated with a space. Like this:
tweets = ['Check out these cool people: #example1 #example2 #example3 #example4 #example5 #example6 #example7 #example8 #example9 #FollowFriday', 'Check out these cool people: #example10 #example11 #example12 #example13 #example14 #example15 #example16 #example17 #FollowFriday', 'Check out these cool people: #example18 #example19 #example20 #FollowFriday']
(The order of the accounts isn't important so theoretically you could try and find the best order to make the most use of the available space, but that's not required.)
Any suggestions? I'm thinking I should use the scan method, but haven't figured out the right way yet.
It's pretty easy using a bunch of loops, but I'm guessing that won't be necessary when using the right Ruby methods. Here's what I came up with so far:
# Create one long string of #usernames separated by a space
tmp = twitter_accounts.map!{|a| a.insert(0, '#')}.join(' ')
# alternative: tmp = '#' + twitter_accounts.join(' #')
# Number of characters left for mentioning the Twitter accounts
length = 140 - (prepend + append).length
# This method would split a string into multiple strings
# each with a maximum length of 'length' and it will only split on empty spaces (' ')
# ideally strip that space as well (although .map(&:strip) could be use too)
tweets = tmp.some_method(' ', length)
# Prepend and append
tweets.map!{|t| prepend + t + append}
P.S.
If anyone has a suggestion for a better title let me know. I had a difficult time summarizing my question.
The String rindex method has an optional parameter where you can specify where to start searching backwards in a string:
arr = %w[example1 example2 example3 example4 example5 example6 example7 example8 example9 example10 example11 example12 example13 example14 example15 example16 example17 example18 example19 example20]
str = arr.map{|name|"##{name}"}.join(' ')
prepend = 'Check out these cool people: '
append = ' #FollowFriday'
max_chars = 140 - prepend.size - append.size
until str.size <= max_chars do
p str.slice!(0, str.rindex(" ", max_chars))
str.lstrip! #get rid of the leading space
end
p str unless str.empty?
I'd make use of reduce for this:
string = %w[example1 example2 example3 example4 example5 example6 example7 example8 example9 example10 example11 example12 example13 example14 example15 example16 example17 example18 example19 example20]
prepend = 'Check out these cool people:'
append = '#FollowFriday'
# Extra -1 is for the space before `append`
max_content_length = 140 - prepend.length - append.length - 1
content_strings = string.reduce([""]) { |result, target|
result.push("") if result[-1].length + target.length + 2 > max_content_length
result[-1] += " ##{target}"
result
}
tweets = content_strings.map { |s| "#{prepend}#{s} #{append}" }
Which would yield:
"Check out these cool people: #example1 #example2 #example3 #example4 #example5 #example6 #example7 #example8 #example9 #FollowFriday"
"Check out these cool people: #example10 #example11 #example12 #example13 #example14 #example15 #example16 #example17 #FollowFriday"
"Check out these cool people: #example18 #example19 #example20 #FollowFriday"

ruby chaining commands inline for a TCL programmer

I am a TCL programmer and do a lot of statement chaining and don't know how that can be done in ruby
For example if i would want to append the current time to the value of a variable
for example in tcl:
set mylist [list a b c,d,e f]
set myelem_with_time "[lindex [split [lindex $mylist 2] ,] 0][clock seconds]"
>>c{with some time value}
How can this be achieved in ruby without using separate lines for each command
(of course its not an object class method or else use . operator, for example chaining the current time, or some arithmetic operation etc)
psudo code:
myval = mylist[2].split(",")[0] + time()+60seconds;
(I want to interpolate the time + 60 without calculating on a previous line)
mylist = %w[a b c,d,e f]
myelem_with_time = mylist[2].split(',')[0] + (Time.now + 60).to_i.to_s
# or
myelem_with_time = "%s%d" % [mylist[2].split(',')[0], (Time.now + 60).to_i]
# or
myelem_with_time = "#{mylist[2].split(',')[0]}#{(Time.now + 60).to_i}"
Using your list from above and playing with your command:
mylist[2].split(",")[0] + (Time.now + 60).to_s
I got:
e f2012-02-28 04:46:55 -0700
Is that what you're looking for (I did not strip the Date from the output but that is possible)

Is there a SnakeYaml DumperOptions setting to avoid double-spacing output?

I seem to see double-spaced output when parsing/dumping a simple YAML file with a pipe-text field.
The test is:
public void yamlTest()
{
DumperOptions printOptions = new DumperOptions();
printOptions.setLineBreak(DumperOptions.LineBreak.UNIX);
Yaml y = new Yaml(printOptions);
String input = "foo: |\n" +
" line 1\n" +
" line 2\n";
Object parsedObject = y.load(new StringReader(input));
String output = y.dump(parsedObject);
System.out.println(output);
}
and the output is:
{foo: 'line 1
line 2
'}
Note the extra space between line 1 and line 2, and after line 2 before the end of the string.
This test was run on Mac OS X 10.6, java version "1.6.0_29".
Thanks!
Mark
In the original string you use literal style - it is indicating by the '|' character. When you dump your text, you use single-quoted style which ignores the '\n' characters at the end. That is why they are repeated with the empty lines.
Try to set different styles in DumperOptions:
// and others - FOLDED, DOUBLE_QUOTED
DumperOptions.setDefaultScalarStyle(ScalarStyle.LITERAL)

Resources