Question

I have a situation in which I want to separate an array initialized with nils into the empty segments and segments containing consecutive runs of numbers.

I found the higher order chunk function of Array to provide an elegant solution to this:

<< [nil,nil,1,2,nil,3].chunk { |e| !e.nil? }.each { |e| p e }

>> [false, [nil, nil]]
>> [true, [1, 2]]
>> [false, [nil]]
>> [true, [3]]

However, suppose that I would like the output to also include the starting index into the original array in each chunk, i.e. augmenting the output above to something like:

>> [false, 0, [nil, nil]]
>> [true, 2, [1, 2]]
>> [false, 4, [nil]]
>> [true, 5, [3]]

Is there a solution to obtaining this that retains the expressiveness of the chunk snippet in the above?

Thanks in advance.

Était-ce utile?

La solution

A functional modular approach: index the input array, chunk, and map it to the desired output, O(n):

data = xs.each_with_index.chunk { |x, i| !x.nil? }.map do |match, pairs| 
  [match, pairs.first[1], pairs.map(&:first)] 
end
#=> [[false, 0, [nil, nil]], [true, 2, [1, 2]], [false, 4, [nil]], [true, 5, [3]]]

Autres conseils

You can just walk through the output of chunk and track starting index yourself. Simply increment it by length of each chunk. Here's my quick attempt.

chunked = [nil,nil,1,2,nil,3].chunk { |e| !e.nil? }

_, chunks_with_embedded_index = chunked.each_with_object([0, []]) do |(k, chunk), memo|
  memo[1] << [k, memo[0], chunk]
  memo[0] += chunk.length
end

chunks_with_embedded_index.each {|c| p c }
# >> [false, 0, [nil, nil]]
# >> [true, 2, [1, 2]]
# >> [false, 4, [nil]]
# >> [true, 5, [3]]

You can extract the temp var for last index into a full local variable and have somewhat cleaner implementation:

chunked = [nil,nil,1,2,nil,3].chunk { |e| !e.nil? }

last_index = 0
chunks_with_embedded_index = chunked.reduce([]) do |memo, (k, chunk)|
  memo << [k, last_index, chunk]
  last_index += chunk.length
  memo
end

chunks_with_embedded_index.each {|c| p c }
# >> [false, 0, [nil, nil]]
# >> [true, 2, [1, 2]]
# >> [false, 4, [nil]]
# >> [true, 5, [3]]
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top