Удалить смежные идентичные элементы в Массиве Ruby?

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] }

Кто-либо может придумать что-то менее ужасное?

10
задан Mike Woodhouse 25 March 2010 в 14:29
поделиться

6 ответов

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

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

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

21
ответ дан 3 December 2019 в 15:21
поделиться
a.inject([]){|acc,i| acc.last == i ? acc : acc << i }
5
ответ дан 3 December 2019 в 15:21
поделиться

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

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! звоните и вы разбираетесь.

1
ответ дан 3 December 2019 в 15:21
поделиться

Я могу думать только о this

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

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

0
ответ дан 3 December 2019 в 15:21
поделиться

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

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
ответ дан 3 December 2019 в 15:21
поделиться

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

1
ответ дан 3 December 2019 в 15:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: