I'm trying to learn some ruby.
Imagine I'm looping and doing a long running process, and in this process I want to get a spinner for as long as necessary.
So I could do:
a=['|','/','-','\\']
aNow=0
# ... skip setup a big loop
print a[aNow]
aNow += 1
aNow = 0 if aNow == a.length
# ... do next step of process
print "\b"
But I thought it'd be cleaner to do:
def spinChar
a=['|','/','-','\\']
a.cycle{|x| yield x}
end
# ... skip setup a big loop
print spinChar
# ... do next step of process
print "\b"
Of course the spinChar call wants a block. If I give it a block it'll hang indefinitely.
How can I get just the next yeild of this block?
Ruby's yield does not work in the way your example would like. But this might be a good place for a closure:
def spinner()
state = ['|','/','-','\\']
return proc { state.push(state.shift)[0] }
end
spin = spinner
# start working
print spin.call
# more work
print spin.call
# etc...
In practice I think this solution might be too "clever" for its own good, but understanding the idea of Procs could be useful anyhow.
I like all these suggestions, but I found the Generator in the standard library, and I think it's more along the lines of what I wanted to do:
spinChar=Generator.new{ |g|
['|','/','-','\\'].cycle{ |x|
g.yield x
}
}
#then
spinChar.next
#will indefinitly output the next character.
Plain array index increments with modulus on a frozen array seems to be fastest.
Vlad's thread is nifty but not exactly what I wanted. And in spinner class the one-line increment would be nicer if Ruby supported i++ like GLYPHS[#i++%GLYPHS.length]
Max's spinner closure with push shift seems a little intensive to me, but the resulting syntax is almost exactly like this Generator. At least I think that's a closure with proc in there.
Chuck's with_spinner is actually pretty close to what I wanted, but why break if you don't have to with a Generator as above.
Vadim, thanks for pointing out the generator would be slow.
"Here's a test of 50,000 spins:"
user system total real
"array index" 0.050000 0.000000 0.050000 ( 0.055520)
"spinner class" 0.100000 0.010000 0.110000 ( 0.105594)
"spinner closure" 0.080000 0.030000 0.110000 ( 0.116068)
"with_spinner" 0.070000 0.030000 0.100000 ( 0.095915)
"generator" 6.710000 0.320000 7.030000 ( 7.304569)
I think you were on the right track with cycle. How about something like this:
1.8.7 :001 > spinner = ['|','/','-','\\'].cycle
=> #<Enumerable::Enumerator:0x7f111c165790>
1.8.7 :002 > spinner.next
=> "|"
1.8.7 :003 > spinner.next
=> "/"
1.8.7 :004 > spinner.next
=> "-"
1.8.7 :005 > spinner.next
=> "\\"
1.8.7 :006 > spinner.next
=> "|"
I don't think you quite understand what yield does in Ruby. It doesn't return a value from a block — it passes a value to the block you've passed to the enclosing method.
I think you want something more like this:
def with_spinner
a=['|','/','-','\\']
a.cycle do |x|
print x
$stdout.flush # needed because standard out is usually buffered
yield # this will call the do-block you pass to with_spinner
end
end
with_spinner do
#process here
#break when done
end
Once upon a time, I wrote an array. But it's not just an array, it's an array that has a pointer, so you can call next foreverrr!
http://gist.github.com/55955
Pair this class with a simple iterator or loop and you are golden.
a = Collection.new(:a, :b, :c)
1000.times do |i|
puts a.current
a.next
end
Your code is a bit inside-out, if you'll pardon me saying so. :)
Why not:
class Spinner
GLYPHS=['|','/','-','\\']
def budge
print "#{GLYPHS[#idx = ((#idx || 0) + 1) % GLYPHS.length]}\b"
end
end
spinner = Spinner.new
spinner.budge
# do something
spinner.budge
spinner.budge
# do something else
spinner.budge
Now, if you want something like:
with_spinner do
# do my big task here
end
...then you'd have to use multi-threading:
def with_spinner
t = Thread.new do
['|','/','-','\\'].cycle { |c| print "#{c}\b" ; sleep(1) }
end
yield
Thread.kill(t) # nasty but effective
end
hehe, the answer above mine is all dirty.
a=['|','/','-','\\']
a << a
a.each {|item| puts item}
Related
I have an instance of Enumerator::Generator that yields strings. I need to join them into a single string.
What's a good way of doing this? I notice that * doesn't work. I know I can .map {|x| x} first but that seems rather un-idiomatic
I think in this case I' might reach for inject/reduce (aliases for the same method, reduce as a name makes more sense, to me) with the + operator:
enum.reduce(:+)
# or, passing in a block
enum.reduce(&:+)
As a full example:
# never used Enumerator::Generator directly, but you called it out specifically
# in your question, and this seems to be doing the trick to get it working
enum = Enumerator::Generator.new do |y|
y.yield "ant"
y.yield "bear"
y.yield "cat"
end
p enum.reduce(&:+) # output: "antbearcat"
# crude example of modifying the strings as you join them
p enum.reduce('') { |memo, word| memo += word.upcase + ' ' }
# output: "ANT BEAR CAT "
a=["Raja","gopalan"].to_enum #let's assume this is your enumerator
Write the following code
p a.map(&:itself).join
Or
p a.to_a.join
output
"Rajagopalan"
When I read a text file into memory it brings my text in with '\n' at the end due to the new lines.
["Hello\n", "my\n", "name\n", "is\n", "John\n"]
Here is how I am reading the text file
array = File.readlines('text_file.txt')
I need to do a lot of processing on this text array, so I'm wondering if I should remove the "\n" when I first create the array, or when I do the processing on each element with regex, performance wise.
I wrote some (admittedly bad) test code to remove the "\n"
array = []
File.open('text_file.txt', "r").each_line do |line|
data = line.split(/\n/)
array << data
end
array.flatten!
Is there a better way to do this if I should remove the "\n" when I first create the array?
If I wanted to read the file into a Set instead(for performance), is there a method similar to readlines to do that?
You need to run a benchmark test, using Ruby's built-in Benchmark to figure out what is your fastest choice.
However, from experience, I've found that "slurping" the file, i.e., reading it all in at once, is not any faster than using a loop with IO.foreach or File.foreach. This is because Ruby and the underlying OS do file buffering as the reads occur, allowing your loop to occur from memory, not directly from disk. foreach will not strip the line-terminators for you, like split would, so you'll need to add a chomp or chomp! if you want to mutate the line read in:
File.foreach('/path/to/file') do |li|
puts li.chomp
end
or
File.foreach('/path/to/file') do |li|
li.chomp!
puts li
end
Also, slurping has the problem of not being scalable; You could end up trying to read a file bigger than memory, taking your machine to its knees, while reading line-by-line will never do that.
Here's some performance numbers:
#!/usr/bin/env ruby
require 'benchmark'
require 'fileutils'
FILENAME = 'test.txt'
LOOPS = 1
puts "Ruby Version: #{RUBY_VERSION}"
puts "Filesize being read: #{File.size(FILENAME)}"
puts "Lines in file: #{`wc -l #{FILENAME}`.split.first}"
Benchmark.bm(20) do |x|
x.report('read.split') { LOOPS.times { File.read(FILENAME).split("\n") }}
x.report('read.lines.chomp') { LOOPS.times { File.read(FILENAME).lines.map(&:chomp) }}
x.report('readlines.map.chomp1') { LOOPS.times { File.readlines(FILENAME).map(&:chomp) }}
x.report('readlines.map.chomp2') { LOOPS.times { File.readlines(FILENAME).map{ |s| s.chomp } }}
x.report('foreach.map.chomp1') { LOOPS.times { File.foreach(FILENAME).map(&:chomp) }}
x.report('foreach.map.chomp2') { LOOPS.times { File.foreach(FILENAME).map{ |s| s.chomp } }}
end
And the results:
Ruby Version: 1.9.3
Filesize being read: 42026131
Lines in file: 465440
user system total real
read.split 0.150000 0.060000 0.210000 ( 0.213365)
read.lines.chomp 0.470000 0.070000 0.540000 ( 0.541266)
readlines.map.chomp1 0.450000 0.090000 0.540000 ( 0.535465)
readlines.map.chomp2 0.550000 0.060000 0.610000 ( 0.616674)
foreach.map.chomp1 0.580000 0.060000 0.640000 ( 0.641563)
foreach.map.chomp2 0.620000 0.050000 0.670000 ( 0.662912)
On today's machines a 42MB file can be read into RAM pretty safely. I have seen files a lot bigger than that which won't fit into the memory of some of our production hosts. While foreach is slower, it's also not going to take a machine to its knees by sucking up all memory if there isn't enough memory.
On Ruby 1.9.3, using the map(&:chomp) method, instead of the older form of map { |s| s.chomp }, is a lot faster. That wasn't true with older versions of Ruby, so caveat emptor.
Also, note that all the above processed the data in less than one second on my several years old Mac Pro. All in all I'd say that worrying about the load speed is premature optimization, and the real problem will be what is done after the data is loaded.
I'd use String#chomp:
lines = open('text_file.txt').lines.map(&:chomp)
If you want to get rid of the ending newline character you can either String#chomp or String#rstrip. My preferred method would be chomp.
So you can easily do something like:
lines.map! { |line| line.chomp }
# or
lines.map! { |line| line.rstrip }
mvelez#argo:~$ cat test.txt
Hello
my
name
is
John
One liner:
arr = File.open("test.txt",'r').read.split
Decomposing this in irb
irb(main):002:0> f = File.open("test.txt",'r')
=> #<File:test.txt>
irb(main):003:0> file_contents = f.read
=> "Hello\nmy\nname\nis\nJohn\n\n"
irb(main):004:0> file_contents.split
=> ["Hello", "my", "name", "is", "John"]
I'ld prefer using strip over split in these cases, and doing it right after handling the line for the first time. Using split after readline is overkill imo. So the code snippet would be
array = []
File.open('text_file.txt', "r").each_line do |line|
array << data.strip
end
I am working through Ruby Koans.
The test_the_shovel_operator_modifies_the_original_string Koan in about_strings.rb includes the following comment:
Ruby programmers tend to favor the shovel operator (<<) over the plus
equals operator (+=) when building up strings. Why?
My guess is it involves speed, but I don't understand the action under the hood that would cause the shovel operator to be faster.
Would someone be able to please explain the details behind this preference?
Proof:
a = 'foo'
a.object_id #=> 2154889340
a << 'bar'
a.object_id #=> 2154889340
a += 'quux'
a.object_id #=> 2154742560
So << alters the original string rather than creating a new one. The reason for this is that in ruby a += b is syntactic shorthand for a = a + b (the same goes for the other <op>= operators) which is an assignment. On the other hand << is an alias of concat() which alters the receiver in-place.
Performance proof:
#!/usr/bin/env ruby
require 'benchmark'
Benchmark.bmbm do |x|
x.report('+= :') do
s = ""
10000.times { s += "something " }
end
x.report('<< :') do
s = ""
10000.times { s << "something " }
end
end
# Rehearsal ----------------------------------------
# += : 0.450000 0.010000 0.460000 ( 0.465936)
# << : 0.010000 0.000000 0.010000 ( 0.009451)
# ------------------------------- total: 0.470000sec
#
# user system total real
# += : 0.270000 0.010000 0.280000 ( 0.277945)
# << : 0.000000 0.000000 0.000000 ( 0.003043)
A friend who is learning Ruby as his first programming language asked me this same question while going through Strings in Ruby on the Ruby Koans series. I explained it to him using the following analogy;
You have a glass of water that is half full and you need to refill your glass.
First way you do it by taking a new glass, filling it halfway with water from a tap and then using this second half-full glass to refill your drinking glass. You do this every time you need to refill your glass.
The second way you take your half full glass and just refill it with water straight from the tap.
At the end of the day, you would have more glasses to clean if you choose to pick a new glass every time you needed to refill your glass.
The same applies to the shovel operator and the plus equal operator. Plus equal operator picks a new 'glass' every time it needs to refill its glass while the shovel operator just takes the same glass and refills it. At the end of the day more 'glass' collection for the Plus equal operator.
This is an old question, but I just ran across it and I'm not fully satisfied with the existing answers. There are lots of good points about the shovel << being faster than concatenation +=, but there is also a semantic consideration.
The accepted answer from #noodl shows that << modifies the existing object in place, whereas += creates a new object. So you need to consider if you want all references to the string to reflect the new value, or do you want to leave the existing references alone and create a new string value to use locally. If you need all references to reflect the updated value, then you need to use <<. If you want to leave other references alone, then you need to use +=.
A very common case is that there is only a single reference to the string. In this case, the semantic difference does not matter and it is natural to prefer << because of its speed.
Because it's faster / does not create a copy of the string <-> garbage collector does not need to run.
While a majority of answers cover += is slower because it creates a new copy, it's important to keep in mind that += and << are not interchangeable! You want to use each in different cases.
Using << will also alter any variables that are pointed to b. Here we also mutate a when we may not want to.
2.3.1 :001 > a = "hello"
=> "hello"
2.3.1 :002 > b = a
=> "hello"
2.3.1 :003 > b << " world"
=> "hello world"
2.3.1 :004 > a
=> "hello world"
Because += makes a new copy, it also leaves any variables that are pointing to it unchanged.
2.3.1 :001 > a = "hello"
=> "hello"
2.3.1 :002 > b = a
=> "hello"
2.3.1 :003 > b += " world"
=> "hello world"
2.3.1 :004 > a
=> "hello"
Understanding this distinction can save you a lot of headaches when you're dealing with loops!
While not a direct answer to your question, why's The Fully Upturned Bin always has been one of my favorite Ruby articles. It also contains some info on strings in regards to garbage collection.
code:
c = 0
items.each { |i|
puts i.to_s
# if c > 9 escape the each iteration early - and do not repeat
c++
}
I want to grab the first 10 items then leave the "each" loop.
What do I replace the commented line with? is there a better approach? something more Ruby idiomatic?
While the break solution works, I think a more functional approach really suits this problem. You want to take the first 10 elements and print them so try
items.take(10).each { |i| puts i.to_s }
There is no ++ operator in Ruby. It's also convention to use do and end for multi-line blocks. Modifying your solution yields:
c = 0
items.each do |i|
puts i.to_s
break if c > 9
c += 1
end
Or also:
items.each_with_index do |i, c|
puts i.to_s
break if c > 9
end
See each_with_index and also Programming Ruby Break, Redo, and Next.
Update: Chuck's answer with ranges is more Ruby-like, and nimrodm's answer using take is even better.
break works for escaping early from a loop, but it's more idiomatic just to do items[0..9].each {|i| puts i}. (And if all you're doing is literally printing the items with no changes at all, you can just do puts items[0..9].)
Another option would be
items.first(10).each do |i|
puts i.to_s
end
That reads a little more easily to me than breaking on an iterator, and first will return only as many items as available if there aren't enough.
Another variant:
puts items.first(10)
Note that this works fine with arrays of less than 10 items:
>> nums = (1..5).to_a
=> [1, 2, 3, 4, 5]
>> puts nums.first(10)
1
2
3
4
5
(One other note, a lot of people are offering some form of puts i.to_s, but in such a case, isn't .to_s redundant? puts will automatically call .to_s on a non-string to print it out, I thought. You would only need .to_s if you wanted to say puts 'A' + i.to_s or the like.)
Does this look like what you want?
10.times { |i|
puts items[i].to_s
}
items.each_with_index { |i, c| puts i and break if c <= 9 }
It was asked:
I want to grab the first 10 items then leave the "each" loop.
Use throw and catch to accomplish this, with few changes to the example:
catch(:done) do
c = 0
collected = []
items.each do |item|
collected << item
throw(:done, collected) if c == 9 # started at 0
c += 1
end
collected # if the list is less than 10 long, return what was collected
end
Simply throw the label :done with collected and the catch which is waiting for :done will return collected.
And to "ruby" this up a bit:
catch(:done) do
items.inject([]) do |collected, item|
throw(:done, collected) if collected.size == 10
collected << item # collected gets returned here and populates the first argument of this block
end
end
I do not know why some people refuse to use inject and use reduce instead (they are equivalent) when clearly the empty array given to inject([]) is being injected with items! Anyhow, the inject will return collected if there are less than 10 items.
Most answers are trying to answer what might be the intent of the question instead of what was asked and items.take(10) does make perfect sense in that case. But I can imagine wanting to grab the first items that fit within my $100 budget. Then you can simply:
catch(:done) do
items.inject({items: [], budget: 100}) do |ledger, item|
remainder = ledger[:budget] - item.price
if remainder < 0
throw(:done, ledger)
else
ledger.tap do |this|
this[:items] << item
this[:budget] = remainder
end # tap just returns what is being tapped into, in this case, ledger
end
end
end
How do I do this type of for loop in Ruby?
for(int i=0; i<array.length; i++) {
}
array.each do |element|
element.do_stuff
end
or
for element in array do
element.do_stuff
end
If you need index, you can use this:
array.each_with_index do |element,index|
element.do_stuff(index)
end
limit = array.length;
for counter in 0..limit
--- make some actions ---
end
the other way to do that is the following
3.times do |n|
puts n;
end
thats will print 0, 1, 2, so could be used like array iterator also
Think that variant better fit to the author's needs
I keep hitting this as a top link for google "ruby for loop", so I wanted to add a solution for loops where the step wasn't simply '1'. For these cases, you can use the 'step' method that exists on Numerics and Date objects. I think this is a close approximation for a 'for' loop.
start = Date.new(2013,06,30)
stop = Date.new(2011,06,30)
# step back in time over two years, one week at a time
start.step(stop, -7).each do |d|
puts d
end
The equivalence would be
for i in (0...array.size)
end
or
(0...array.size).each do |i|
end
or
i = 0
while i < array.size do
array[i]
i = i + 1 # where you may freely set i to any value
end
array.each_index do |i|
...
end
It's not very Rubyish, but it's the best way to do the for loop from question in Ruby
To iterate a loop a fixed number of times, try:
n.times do
#Something to be done n times
end
If you don't need to access your array, (just a simple for loop) you can use upto or each :
Upto:
2.upto(4) {|i| puts i}
2
3
4
Each:
(2..4).each {|i| puts i}
2
3
4
What? From 2010 and nobody mentioned Ruby has a fine for /in loop (it's just nobody uses it):
ar = [1,2,3,4,5,6]
for item in ar
puts item
end
['foo', 'bar', 'baz'].each_with_index {|j, i| puts "#{i} #{j}"}
Ruby's enumeration loop syntax is different:
collection.each do |item|
...
end
This reads as "a call to the 'each' method of the array object instance 'collection' that takes block with 'blockargument' as argument". The block syntax in Ruby is 'do ... end' or '{ ... }' for single line statements.
The block argument '|item|' is optional but if provided, the first argument automatically represents the looped enumerated item.