Удалить соседние идентичные элементы в Ruby Array? - PullRequest
10 голосов
/ 25 марта 2010

Рубин 1.8.6

У меня есть массив, содержащий числовые значения. Я хочу уменьшить его так, чтобы последовательности одного и того же значения сводились к одному экземпляру этого значения.

Итак, я хочу

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

уменьшить до

[1, 2, 3, 2, 3]

Как видите, Array#uniq не будет работать в этом случае.

У меня есть следующее, которое работает:

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

Может кто-нибудь придумать что-нибудь менее уродливое?

Ответы [ 6 ]

21 голосов
/ 25 марта 2010

Для самого простого и экономного решения вы можете использовать метод Enumerable#chunk:

a.chunk(&:itself).map(&:first)

Метод itself - это Ruby 2.2+. Используйте {|n| n}, если вы застряли в более старом Ruby, или мои backports драгоценные камни. Он был введен в Ruby 1.9.2. Если вам не повезло использовать старые рубины, вы можете использовать мой драгоценный камень backports и require 'backports/1.9.2/enumerable/chunk'.

5 голосов
/ 25 марта 2010
a.inject([]){|acc,i| acc.last == i ? acc : acc << i }
1 голос
/ 27 марта 2010

Если числа все однозначные, 0-9: a.join.squeeze('0-9').each_char.to_a должно работать.

1 голос
/ 25 марта 2010

другое решение:

acc = [a[0]]
a.each_cons(2) {|x,y| acc << y if x != y}

или

a.each_cons(2).inject([a[0]]) {|acc, (x,y)| x == y ? acc : acc << y}
1 голос
/ 25 марта 2010

Если вы не очень обеспокоены скоростью, с которой будет рассчитываться блок, я бы посоветовал вам просто добавить эту строку в конец вашего блока, чтобы получить желаемый результат:

a.compact!

Это просто удалит все элементы nil, которые вы ввели в массив ранее (потенциальные дубликаты), образуя желаемый результат: [1, 2, 3, 2, 3]

Если вам нужен другой алгоритм, вот что-то гораздо страшнее , чем у вас. : -)

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

Дает вам вывод:

[1, nil, nil, 2, nil, 3, nil, nil, nil, 2, nil, nil, 3, nil, nil]
[1, 2, 3, 2, 3]

На мой взгляд, ваш код в порядке. Просто добавьте a.compact! вызов, и вы отсортированы.

0 голосов
/ 25 марта 2010

Я могу думать только об этом

a.each_with_index{|item,i| a[i] = nil if a[i] == a[i+1] }.compact

но это более или менее то же самое.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...