Closed daveyarwood closed 7 years ago
Crystal behaves here in the same way as Ruby does.
# from Ruby `Enumerable#each_with_index` docs
# works as expected
evens = (1..10).each_with_object([] of Int32) { |i, a| a << i * 2 }
# => [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
Passed String
as an initial value indeed gets returned at the end, because #each_with_index
does not accumulate value, it just passes it as a reference. You could rewrite it to use String::Builder
, like so:
class Raindrops
RULES = [
{3, "Pling"},
{5, "Plang"},
{7, "Plong"}
]
def self.drops(drop)
sounds = RULES.each_with_object(String::Builder.new) do |(n, sound), result|
result << sound if drop % n == 0
end
sounds.empty? ? drop.to_s : sounds.to_s
end
end
# Raindrops.drops(35) # => "PlangPlong"
Hey, you're the guy who works on Alda, right?
@kirbyfan64 yep, hello!
@Sija That makes sense. The String::Builder semantics are the piece I was missing. Thanks!
I noticed this issue when solving the "Raindrops" problem (similar to the classic FizzBuzz) on http://exercism.io.
I had previously solved the same problem in Ruby using
each_with_object("")
to iterate through the rules and build up a string of the applicable sounds. So, I tried to reuse the same code in Crystal and I found thateach_with_object
appears to behave differently.Here is my code:
This code compiles, but it appears that the result is not being accumulated, and the block returns
""
.I was able to get it to work using
reduce
:In Ruby,
reduce
andeach_with_object
both work for the example above. Could this be a bug in the implementation ofeach_with_object
in Crystal?