Ruby 1.8.6
I have an array containing numerical values. I want to reduce it such that sequences of the same value are reduced to a single instance of that value.
For the simplest, leanest solution, you could use the method Enumerable#chunk:
a.chunk(&:itself).map(&:first)
The itself
method is Ruby 2.2+. Use {|n| n}
if you are stuck in an older Ruby, or my backports gems.
It was introduced in Ruby 1.9.2. If you're unlucky enough to be using older rubies, you could use my backports gem and require 'backports/1.9.2/enumerable/chunk'
.
If the numbers are all single digits 0-9: a.join.squeeze('0-9').each_char.to_a
should work.
Unless you are very concerned with the speed that block will calculate at, I would suggest you simply add this line to the end of your block to get the desired output:
a.compact!
That will just remove all the nil
elements you introduced to the array earlier (the would-be duplicates), forming your desired output: [1, 2, 3, 2, 3]
If you want another algorithm, here is something far uglier than yours. :-)
require "pp"
a = [1, 1, 1, 2, 2, 3, 3, 3, 3, 2, 2, 2, 3, 3, 3]
i = 0
while i < a.size do
e = a[i]
j = i
begin
j += 1
end while e == a[j]
for k in i+1..j-1 do
a[k] = nil
end
i = j
end
pp a
a.compact!
pp a
Gives you the output:
[1, nil, nil, 2, nil, 3, nil, nil, nil, 2, nil, nil, 3, nil, nil]
[1, 2, 3, 2, 3]
In my opinion, your code is fine. Just add the a.compact!
call and you are sorted.
a.inject([]){|acc,i| acc.last == i ? acc : acc << i }
another solution:
acc = [a[0]]
a.each_cons(2) {|x,y| acc << y if x != y}
or
a.each_cons(2).inject([a[0]]) {|acc, (x,y)| x == y ? acc : acc << y}
I can think only of this
a.each_with_index{|item,i| a[i] = nil if a[i] == a[i+1] }.compact
but it is more or less the same.