Я хотел бы взять вход, такие как:Как суммировать массив целых чисел как массив диапазонов?
[1,2,4,5,6,7,9,13]
и превратить его в нечто вроде следующего:
[[1,2],[4,7],[9,9],[13,13]]
Каждый суб-массив представляет собой набор целых чисел.
Я хотел бы взять вход, такие как:Как суммировать массив целых чисел как массив диапазонов?
[1,2,4,5,6,7,9,13]
и превратить его в нечто вроде следующего:
[[1,2],[4,7],[9,9],[13,13]]
Каждый суб-массив представляет собой набор целых чисел.
Функциональный подход с использованием Enumerable#chunk:
xs.enum_for(:chunk).with_index { |x, idx| x - idx }.map do |diff, group|
[group.first, group.last]
end
# => [[1, 2], [4, 7], [9, 9], [13, 13]]
Как это работает: когда индексируются, последовательные элементы массива имеют одинаковый x - idx
, поэтому мы используем это значение для фрагмента (группировку последовательных элементов) входной массив. Наконец, нам просто нужно взять первый и последний элементы каждой группы для построения пар.
Это выглядит очень хорошо. Полностью забыл о новом методе куска. – cvshepherd
И еще один шаг: '.map {| min, max | min == max? min: min .. max} 'приведет к:' [1..2, 4..7, 9, 13] '. –
Или измените '[pairs.first [0], pairs.last [0]]' на 'pairs.first [0] .. pairs.last [0]', чтобы получить диапазоны во всех позициях: '[1. .2, 4..7, 9..9, 13..13] '. –
Другой подход
def summarize(x)
x.inject([]) do |acc, value|
if acc.last && acc.last[1] + 1 == value
acc.last[1] = value
acc
else
acc << [value,value]
end
end
end
Подобно методу Larsenal, но с помощью инъекции, чтобы управлять скучные вещи.
Хм, ну, это не tokland's шедевр, но я думаю, что это может быть хорошим простое решение ...
[1,2,4,5,6,7,9,13].inject([]) do |m, v|
if m.last.to_a.last == v.pred
m[-1][-1] = v
else
m << [v, v]
end
m
end
Это почти прямо из документации enumerable#slice_before метода:
ar = [1,2,4,5,6,7,9,13]
prev = ar[0]
ar.slice_before{|e|prev,prev2 = e,prev; prev2.succ != e}.map{|a|a.first..a.last}
#=> [1..2, 4..7, 9..9, 13..13]
Это должно работать с символами, датами, с помощью метода .succ
.
Еще проще, чем решение @tokland's very nice one использует chunk_while
:
xs.chunk_while { |a, b| a + 1 == b }.map do |seq|
[seq.first, seq.last]
end
Примечание: chunk_while
был введен в Рубине 2.3
Вы спрашиваете, если есть код, чтобы сделать это уже? Вы спрашиваете, потому что вы пытаетесь катиться самостоятельно и не можете его реализовать? – bobbymcr
Я катаюсь самостоятельно. Кажется, всегда есть интересные способы реализовать подобные вещи в Ruby. – Larsenal
По каким условиям должны быть построены диапазоны? – cvshepherd