Удалить соседние идентичные элементы в Ruby Array?
Ruby 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] }
Может ли кто-нибудь придумать что-то менее уродливое?
Ответы
Ответ 1
Для самого простого и легкого решения вы можете использовать метод Enumerable#chunk
:
a.chunk(&:itself).map(&:first)
itself
метод - Ruby 2. 2+. Используйте {|n| n}
{|n| n}
если вы застряли в более старом Ruby или в моих backports
. Он был введен в Ruby 1.9.2. Если вам не повезло использовать старые рубины, вы можете использовать мой драгоценный камень backports и require 'backports/1.9.2/enumerable/chunk'
.
Ответ 2
a.inject([]){|acc,i| acc.last == i ? acc : acc << i }
Ответ 3
Если вы не очень заинтересованы в скорости, которую рассчитывает блок, я бы предложил вам просто добавить эту строку в конец вашего блока, чтобы получить желаемый результат:
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!
, и вы отсортированы.
Ответ 4
другое решение:
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}
Ответ 5
Если все цифры равны 0-9: a.join.squeeze('0-9').each_char.to_a
должны работать.
Ответ 6
Я могу думать только об этом
a.each_with_index{|item,i| a[i] = nil if a[i] == a[i+1] }.compact
но он более или менее одинаковый.