Ruby 将非零数字和连续时间分组
Ruby group non-zero numbers and sequential times
我有一组这样的项目:[DateTime, value]
。我想对满足以下条件的项目进行分组:
- 3 个或更多项的序列
- 项目包含的值 > 0
- 时间是连续的(增加1秒)
我想获取满足这些条件的序列开始和结束的索引。
例如
[
[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],
]
应该return:
[ [0,2] ]
我查看了 Daru and NMatrix,但我不知道如何进行顺序比较来完成我想做的事情。
现在我有了一个可以进行大量比较的大循环 - 有更好的方法吗?
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]]
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 (new in MRI v2.2) is closely related to 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
时 return 值相同。)如果愿意,子句
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] }
我有一组这样的项目:[DateTime, value]
。我想对满足以下条件的项目进行分组:
- 3 个或更多项的序列
- 项目包含的值 > 0
- 时间是连续的(增加1秒)
我想获取满足这些条件的序列开始和结束的索引。
例如
[
[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],
]
应该return:
[ [0,2] ]
我查看了 Daru and NMatrix,但我不知道如何进行顺序比较来完成我想做的事情。
现在我有了一个可以进行大量比较的大循环 - 有更好的方法吗?
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]]
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 (new in MRI v2.2) is closely related to 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
时 return 值相同。)如果愿意,子句
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] }