Tell me more ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

Can anyone come up with a functional (no mutating variables) way in ruby to do the following?

Given this sorted data:

data = [{1 => "A"},
        {2 => "B"},
        {3 => "B"},
        {4 => "C"},
        {5 => "D"},
        {6 => "D"},
        {7 => "D"}]

Yield this

[{"start" => 1, "end" => 1, "value" => "A"},
 {"start" => 2, "end" => 3, "value" => "B"},
 {"start" => 4, "end" => 4, "value" => "C"},
 {"start" => 5, "end" => 7, "value" => "D"}]
share|improve this question
Accepting the answer below, but there's also this one-liner: data.group_by {|h| h.values.first }.map {|v, a| {"start" => a.first.keys.first, "end" => a.last.keys.first, "value" => v } } – Ron Garrity Aug 22 '12 at 13:41
It's preferable to create an answer if you find a better solution than selecting one you're not happy with. – tokland Aug 27 '12 at 8:04

2 Answers

up vote 1 down vote accepted
# v = data.map{|d| d.values[0]}
# k = data.map{|d| d.keys[0]}

k,v = [:keys, :values].map{|m| data.map{|d| d.send(m)[0]}}

seq = v.sort.uniq.map{|x| {:start => k[v.index(x)], :stop => k[v.rindex(x)], :value => x} }
seq.each do |p|
  p p
end
share|improve this answer
I liked your functional snippet in the other question, but this snippet is very, very dubious. It's hard to understand, and those repeated calls to rindex (each one O(n)) won't have good performance. Starting from chunk or group_by is preferable. – tokland Aug 25 '12 at 19:48
Thanks, I agree. The solution posted by the op is better. – rahul Aug 26 '12 at 15:17

You need the abstraction "group consecutive elements by a given criterion", that's Enumerable#chunk:

data.chunk { |h| h.values.first }.map do |value, hs| 
  {"start" => hs.first.keys[0], "end" => hs.last.keys[0], "value" => value}
end

But note that this solution required some ugly gymnastics on the hash/array transformations. That's because the original data structure is not quite right, what sense does it make to have hashes with a single element? a simple pair will do. If you do that transformation on the data, the resulting code is easier to understand:

data.map(&:first).chunk { |index, char| char }.map do |char, pairs| 
  {"start" => pairs.first[0], "end" => pairs.last[0], "value" => char}
end
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.