gpt4 book ai didi

ruby - 计算ruby中两个范围(日期)数组的交集

转载 作者:太空宇宙 更新时间:2023-11-03 16:24:14 24 4
gpt4 key购买 nike

给定两个大范围数组...

A = [0..23, 30..53, 60..83, 90..113]
B = [-Float::INFINITY..13, 25..33, 45..53, 65..73, 85..93]

当我执行 logical conjuction 时...

C = A.mask(B)

那么我期待

describe "Array#mask" do
it{expect(C = A.mask(B)).to eq([0..13, 30..33, 45..53, 65..73, 90..93])}
end

感觉应该是……

C = A & B
=> []

但那是空的because none of the ranges are identical .

这是一个图片示例。

Logical conjuction waveform .

我将 Infinity 包括在范围内是因为此问题的解决方案 typically involve converting the Range to an Array or Set .

我的当前解决方案这是我目前通过速度和准确性测试的解决方案。我正在寻找评论和/或建议的改进。第二个测试使用优秀的IceCube gem to generate an array of date ranges .我的掩码方法中有一个隐含的假设,即每个计划中出现的日期范围不重叠。

require 'pry'
require 'rspec'
require 'benchmark'
require 'chronic'
require 'ice_cube'
require 'active_support'
require 'active_support/core_ext/numeric'
require 'active_support/core_ext/date/calculations'

A = [0..23, 30..53, 60..83, 90..113]
B = [-Float::INFINITY..13, 25..33, 45..53, 65..73, 85..93]

class Array
def mask(other)
a_down = self.map{|r| [:a, r.max]}
a_up = self.map{|r| [:a, r.min]}

b_down = other.map{|r| [:b, r.max]}
b_up = other.map{|r| [:b, r.min]}

up = a_up + b_up
down = a_down + b_down

a, b, start, result = false, false, nil, []
ticks = (up + down).sort_by{|i| i[1]}
ticks.each do |tick|
tick[0] == :a ? a = !a : b = !b
result << (start..tick[1]) if !start.nil?
start = a & b ? tick[1] : nil
end
return result
end
end

describe "Array#mask" do
context "simple integer array" do
it{expect(C = A.mask(B)).to eq([0..13, 30..33, 45..53, 65..73, 90..93])}
end

context "larger date ranges from IceCube schedule" do
it "should take less than 0.1 seconds" do
year = Time.now..(Time.now + 52.weeks)
non_premium_schedule = IceCube::Schedule.new(Time.at(0)) do |s|
s.duration = 12.hours
s.add_recurrence_rule IceCube::Rule.weekly.day(:monday, :tuesday, :wednesday, :thursday, :friday).hour_of_day(7).minute_of_hour(0)
end
rota_schedule = IceCube::Schedule.new(Time.at(0)) do |s|
s.duration = 7.hours
s.add_recurrence_rule IceCube::Rule.weekly(2).day(:tuesday).hour_of_day(15).minute_of_hour(30)
end
np = non_premium_schedule.occurrences_between(year.min, year.max).map{|d| d..d+non_premium_schedule.duration}
rt = rota_schedule.occurrences_between(year.min, year.max).map{|d| d..d+rota_schedule.duration}
expect(Benchmark.realtime{np.mask(rt)}).to be < 0.1
end
end
end

你不能用Ruby现有的核心方法来做这件事,感觉很奇怪?我错过了什么吗?我发现自己相当定期地计算范围交叉点。

我还想到,您可以使用相同的方法通过传递单个项目数组来查找两个单个范围之间的交集。例如

[(54..99)].mask[(65..120)]

我意识到我已经回答了我自己的问题,但我想我会把它留在这里作为其他人的引用。

最佳答案

我不确定我是否真的理解你的问题;我对你的 expect 声明有点困惑,我不知道为什么你的数组大小不一样。也就是说,如果你想计算两个范围的交集,我喜欢这个猴子补丁(来自 Ruby: intersection between two ranges ):

class Range
def intersection(other)
return nil if (self.max < other.begin or other.max < self.begin)
[self.begin, other.begin].max..[self.max, other.max].min
end
alias_method :&, :intersection
end

然后你可以做:

A = [0..23, 30..53, 60..83, 0..0, 90..113]
B = [-Float::INFINITY..13, 25..33, 45..53, 65..73, 85..93]

A.zip(B).map { |x, y| x & y }
# => [0..13, 30..33, nil, nil, 90..93]

这似乎是一个合理的结果......

编辑

如果你按照上面的方式对 Range 进行 monkeypatch,然后执行:

# your initial data
A = [0..23, 30..53, 60..83, 90..113]
B = [-Float::INFINITY..13, 25..33, 45..53, 65..73, 85..93]

A.product(B).map {|x, y| x & y }.compact
# => [0..13, 30..33, 45..53, 65..73, 90..93]

您会得到您指定的结果。不知道它如何在性能方面进行比较,而且我不确定排序顺序...

关于ruby - 计算ruby中两个范围(日期)数组的交集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27899934/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com