Ненулевые числа в рубиновой группе и последовательные времена - PullRequest
0 голосов
/ 06 ноября 2018

У меня есть массив элементов вроде: [DateTime, value]. Я хочу сгруппировать элементы, которые удовлетворяют следующим условиям:

  • Последовательность из 3 или более предметов
  • Элементы содержат значения> 0
  • раз подряд (увеличение на 1 секунду)

Я хочу получить индексы начала и конца последовательностей, которые удовлетворяют этим условиям.

* 1014 Е.Г. *

[ 
[today 10:00:00, 1],
[today 10:00:01, 1],
[today 10:00:02, 1],
[today 10:00:03, 0],
[today 10:00:04, 1],
[today 10:00:05, 1],
[today 10:00:16, 1],
[today 10:00:17, 1],
]

Должен вернуться:

[ [0,2] ]

Я посмотрел на Дару и NMatrix , но я не мог понять, как проводить последовательные сравнения, чтобы делать то, что я хочу.

Теперь у меня есть большой цикл, который делает много сравнений - есть ли лучший способ сделать это?

Ответы [ 2 ]

0 голосов
/ 07 ноября 2018
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] }
0 голосов
/ 06 ноября 2018
t = Time.now
a = [
  [t + 0, 1],
  [t + 1, 1],
  [t + 2, 1],
  [t + 3, 0],
  [t + 4, 1],
  [t + 5, 1],
  [t + 16, 1],
  [t + 17, 1],
]

a
.each_with_index
.chunk_while{
  |(x, i), (y, j)|
  x[1].positive? and
  y[1].positive? and
  x[0].to_i.next == y[0].to_i
}
.select{|chunk| chunk.length >= 3}
.map{|chunk| [chunk.first[1], chunk.last[1]]}
# => [[0, 2]]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...