给出以下数组间隔:
today = Time.current.beginning_of_day
tomorrow = Time.current.tomorrow.beginning_of_day
availabilities = {
monday: [
{ start_time: today + 6.hours,
end_of_time: today + 12.hours },
{ start_time: today + 8.hours,
end_of_time: today + 18.hours }
],
tuesday: [
{ start_time: tomorrow + 10.hours,
end_time: tomorrow + 16.hours },
{ start_time: tomorrow + 18.hours,
end_time: tomorrow + 23.hours }
]
}
如何以这样的方式构建availabilities
数组,例如在monday
和tuesday
哈希的情况下:
# monday
{ start_time: 'Today at 06:00',
end_time: 'Today at 18:00' }
# tuesday
[ { start_time: 'Tomorrow at 10:00',
end_time: 'Tomorrow at 16:00' },
{ start_time: 'Tomorrow at 18:00',
end_time: 'Tomorrow at 23:00' } ]
我想要实现的是获取给定日期的可用时间间隔,而不管哪个实体将提供该可用性。
在此先感谢,我们非常感谢您使用哪种算法的任何帮助或指导。
答案 0 :(得分:2)
证明它有效:
如果区间A,B和C被排序,并且A和C重叠,则也意味着B肯定与A重叠。
这是在Ruby中实现这一点的一种方法。
def overlap?(r1, r2)
!(r1.end <= r2.begin || r1.begin >= r2.end)
end
def merge_intervals(r1, r2)
[r1.begin, r2.begin].min..[r1.end, r2.end].max
end
def flatten_intervals(intervals)
first, *rest = intervals.sort_by(&:begin)
rest.each_with_object([first]) { |r,stack| stack <<
(overlap?(stack.last, r) ? merge_intervals(stack.pop, r) : r) }
end
intervals = [0..2, 5..8, 4..9, 11..13, 15..17, 19..21, 17..19, 16..20]
flatten_intervals(intervals)
#=> [0..2, 4..9, 11..13, 15..21]
答案 1 :(得分:1)
这是将时间间隔数组转换为非重叠时间间隔数组的简便方法。我假设粒度是一小时(但是将其更改为分钟或秒是很简单的)。为方便起见,我还将时间间隔表示为范围而不是问题中指定的哈希值(尽管将范围转换为哈希值很容易)。
假设
time_intervals = [0..2, 5..8, 4..9, 11..13, 15..17, 19..21, 17..19, 16..20]
我们可以按如下方式查看这些间隔:
00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23
xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx
xx xx xx xx xx xx xx xx xx
xx xx xx xx xx
我们希望如此结合这些:
00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23
xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx
一种简单的方法如下。
h = 24.times.with_object({}) { |i,h| h[i] = :uncovered }
time_intervals.each { |range|
(range.begin..range.end).each { |i| h[i] = :covered } }
h.delete_if { |_,v| v == :uncovered }.
keys.
slice_when { |k1, k2| k2 - k1 > 1 }.
map { |a| a.first..a.last }
#=> [0..2, 4..9, 11..13, 15..21]
步骤如下。
h = 24.times.with_object({}) { |i,h| h[i] = :uncovered }
#=> {0=>:uncovered, 1=>:uncovered, 2=>:uncovered,..., 23=>:uncovered}
time_intervals.each { |range|
(range.begin..range.end).each { |i| h[i] = :covered } }
h #=> { all k=>:covered except k=>:uncovered for k = 3, 10, 14, 22 and 23 }
g = h.delete_if { |_,v| v == :uncovered }
#=> { all k=>:covered, k = 1,2, 4,5,6,7,8,9, 11,12,13, 15,16,17,18,19,20,21v]
k = g.keys
#=> [0, 1, 2, 4, 5, 6, 7, 8, 9, 11, 12, 13, 15, 16, 17, 18, 19, 20, 21]
e = k.slice_when { |k1, k2| k2 - k1 > 1 }
#=> #<Enumerator: #<Enumerator::Generator:0x007fee0a05c7b0>:each>
我们可以看到这个枚举器生成的元素如下:
e.entries
#=> [[0, 1, 2], [4, 5, 6, 7, 8, 9], [11, 12, 13], [15, 16, 17, 18, 19, 20, 21]]
见Enumerable#entries。也可以使用Enumerable#to_a。
最后一步是将数组转换为范围。
e.map { |a| a.first..a.last }
#=> [0..2, 4..9, 11..13, 15..21]
答案 2 :(得分:1)
合并重叠间隔的算法:
1. Sort the intervals on start time
2. Assign left and right of first interval (0)
3. Iterate over the intervals from 1 to size-1
if (current interval start lies in prev. interval)
update right to max(prev. right, current. right)
else
[left, right] is non-overlapping interval => push it to answer array
reassign left and right to current interval
4. push last [left, right] to answer array
解决方案:
# hash of overlapping intervals
availabilities = {
monday: [
{ start_time: 6,
end_time: 12 },
{ start_time: 8,
end_time: 18 }
],
tuesday: [
{ start_time: 10,
end_time: 16 },
{ start_time: 18,
end_time: 23 }
]
}
# function for converting hash to intervals, process, and then convert back to hash
def solve(list)
return_hash = {}
list.each do |key, arr|
intervals = []
arr.each { |hash| intervals << [hash[:start_time], hash[:end_time]] }
non_overlapping_intervals = merge_interval(intervals)
temp = []
non_overlapping_intervals.each { |interval| temp << {start_time: interval[0], end_time: interval[1]} }
return_hash[key] = temp
end
return_hash
end
# algorithm to merge intervals and return non-overlapping intervals
def merge_interval(v)
intervals = []
v.sort()
size = v.size()
l, r = v[0][0], v[0][1]
(1...size).each do |i|
if v[i][0] <= r
r = [r,v[i][1]].max;
else
intervals << [l, r]
l, r = v[i][0], v[i][1]
end
end
intervals << [l, r]
return intervals
end
# solve call for availabilities hash
p solve(availabilities)
输出:
{
:monday=>[{:start_time=>6, :end_time=>18}],
:tuesday=>[{:start_time=>10, :end_time=>16},
{:start_time=>18, :end_time=>23}]
}
答案 3 :(得分:0)
格式略有不同(Range而不是具有不一致键的哈希),这个问题变得更容易:
public class TheFragment extends Fragment {
TextView tv;
public TheFragment() {
}
String value = getArguments().getString("key");
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/* if(value!=null){
tv.setText(value);
} */
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_this, container, false);
tv = (TextView) getView().findViewById(R.id.thePrice);
tv.setText(value);
return view;
}
}
然后,您可以使用range-operator gem对范围求和。