Reputation: 3760
I want to process the array ['a', 'b', 'c']
to return the string '0a1b2c'
(i.e, string formed by concatenating each index with its value).
I can do this:
result = ''
['a', 'b', 'c'].each.with_index do |char, i|
result += "#{i}#{char}"
end
result
I want to eliminate the result variable outside the block by using with_object.
Something like this:
['a', 'b', 'c'].each.with_index.with_object('') do |char, i, result|
result += "#{i}#{char}"
end
But this raises an error undefined method '+' for nil:NilClass
Upvotes: 2
Views: 1016
Reputation: 1
Something important about this solution, which is nice :
%w|a b c|.each_with_object('').with_index do |(char, result), i|
result << "#{i}#{char}"
end
Here we use <<
instead of +=
.
with_object
only works with mutable objects, and you might think that string is mutable, so why wouldn't we be able to use +=
? Because +=
is equivalent to x = x+y
, so it generates a new object each time.
In the end, if you use +=
with with_object
, you never mutate the original object you created, you just create a new object you won't keep track of in the block at each iteration.
More details here: How is each_with_object supposed to work?
Upvotes: 0
Reputation: 54223
It doesn't use the methods you ask for, but it does the job and is relatively compact :
array = ['a', 'b', 'c']
(0...array.size).zip(array).join
#=> "0a1b2c"
Upvotes: 2
Reputation: 27793
Try this
arr.each.with_index.with_object('') { |(each, n), obj| ... }
How does this work?
with_index
and with_object
creates nested tuples(each, n), obj
unpacks both tuplesFun fact—or maybe rather sad fact—the nested tuple actually materialized as a short-lived array so this will create O(n)
arrays. If this is a critical production codepath I would away nesting these two enumeration functions. Since you most likely are going to assign obj
to a variable in the outer scope anyway it would make most sense to rewrite this as
obj = ''
arr.each_with_index { |each, n| ... }
Upvotes: 3
Reputation: 121000
Both operations should be done without abusing each
iterator:
%w|a b c|.map.with_index do |char, i|
"#{i}#{char}"
end.join
%w|a b c|.each_with_object('').with_index do |(char, result), i|
result << "#{i}#{char}"
end
Or, if you still want to use each:
%w|a b c|.each.with_index.with_object('') do |char_idx, result|
result << char_idx.join
end
Upvotes: 1