Tutorial :Remove adjacent identical elements in a Ruby Array?



Question:

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.

So I want

a = [1, 1, 1, 2, 2, 3, 3, 3, 3, 2, 2, 2, 3, 3, 3]  

to reduce to

[1, 2, 3, 2, 3]  

As you can see, Array#uniq won't work in this case.

I have the following, which works:

(a.size - 1).downto(1) { |i| a[i] = nil if a[i - 1] == a[i] }  

Can anyone come up with something less ugly?


Solution:1

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'.


Solution:2

a.inject([]){|acc,i| acc.last == i ? acc : acc << i }  


Solution:3

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.


Solution:4

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}  


Solution:5

If the numbers are all single digits 0-9: a.join.squeeze('0-9').each_char.to_a should work.


Solution:6

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.


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »