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] }
Кто-либо может придумать что-то менее ужасное?
Для простейшего и экономичного решения вы можете использовать метод 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'
.
a.inject([]){|acc,i| acc.last == i ? acc : acc << i }
Если вас не очень беспокоит скорость, с которой блок будет вычислять, я бы посоветовал вам просто добавить эту строку в конец ваш блок, чтобы получить желаемый результат:
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!
звоните и вы разбираетесь.
Я могу думать только о this
a.each_with_index{|item,i| a[i] = nil if a[i] == a[i+1] }.compact
, но это более или менее то же самое.
другое решение:
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}
Если все числа состоят из одних цифр 0-9: a.join.squeeze('0-9').each_char.to_a
должно сработать.