t = Time.now
arr = [[t+ 0, 1], [t+ 1, 1], [t+ 2, 1], [t+ 3, 0], [t+ 4, 1], [t+ 5, 1], [t+16, 1],
[t+18, 1], [t+19, 1], [t+20, 1], [t+21, 1], [t+30, 1]]
#=> [[2018-11-06 10:11:52 -0800, 1], [2018-11-06 10:11:53 -0800, 1],...,
# [2018-11-06 10:12:22 -0800, 1]]
arr.each_index.
slice_when { |i,j| arr[i].last.zero? || arr[i-1].last.zero? ||
(arr[i].first - arr[i-1].first > 1) }.
each_with_object([]) { |a,b| b << [a.first, a.last] if a.last-a.first >= 2 }
#=> [[0, 2], [7, 10]]
Emumerable # slice_when (новый в MRI v2.2) тесно связан с Enumerable # chunk_ while (новый в MRI v2.3), который @sawa использовал в своем ответе. Как правило, если один из них можно использовать, другой является альтернативой.
Для поддержки более ранних версий Ruby можно использовать Enumerable # slice_before (новое в MRI v1.9.2).
arr.each_index.
slice_before { |i| i > 0 &&
(arr[i].last.zero? || arr[i-1].last.zero? || (arr[i].first - arr[i-1].first > 1)) }.
each_with_object([]) { |a,b| b << [a.first, a.last] if a.last-a.first >= 2 }
Обратите внимание на промежуточный расчет:
enum = arr.each_index.slice_before {|i| i > 0 &&
(arr[i].last.zero? || arr[i-1].last.zero? || (arr[i].first - arr[i-1].first > 1)) }
#=> => #<Enumerator: #<Enumerator::Generator:0x0000000001948d50>:each>
enum.to_a
#=> [[0, 1, 2], [3], [4, 5], [6], [7, 8, 9, 10], [11]]
(Возвращаемое значение одинаково при использовании slice_when
.) Если предпочтительнее, предложение
each_with_object([]) { |a,b| b << [a.first, a.last] if a.last-a.first >= 2 }
можно заменить двухпроходной альтернативой:
select { |a| a.last - a.first >= 2 }.map { |a| [a.first, a.last] }