Ruby on rails 基于比较相邻元素的Ruby/Rails组数组
我有一个有序的数组,里面有很多对象,我想通过将它们与周围的元素进行比较来对它们进行分组Ruby on rails 基于比较相邻元素的Ruby/Rails组数组,ruby-on-rails,ruby,arrays,Ruby On Rails,Ruby,Arrays,我有一个有序的数组,里面有很多对象,我想通过将它们与周围的元素进行比较来对它们进行分组 a按start属性排序 a = [{ name: "joe", start: "9am", end: "10am" }, { name: "joe", start: "10am", end: "11am" }, { name: "harry", start: "11am", end: "12pm" }, { name: "harry", start: "12pm
a
按start
属性排序
a = [{ name: "joe", start: "9am", end: "10am" },
{ name: "joe", start: "10am", end: "11am" },
{ name: "harry", start: "11am", end: "12pm" },
{ name: "harry", start: "12pm", end: "1pm" },
{ name: "harry", start: "2pm", end: "3pm" },
{ name: "joe", start: "3pm", end: "4pm" },
{ name: "joe", start: "4pm", end: "5pm" }]
我想按name
属性对相邻对象进行分组,但前提是start
和end
时间相同,从而产生:
a = [[{ name: "joe", start: "9am", end: "10am" }, { name: "joe", start: "10am", end: "11am" }],
[{ name: "harry", start: "11am", end: "12pm" }, { name: "harry", start: "12pm", end: "1pm" }],
[{ name: "harry", start: "2pm", end: "3pm" }],
[{ name: "joe", start: "3pm", end: "4pm" }, { name: "joe", start: "4pm", end: "5pm" }]]
连续时间段的数量没有最大值
我可以按
名称对它们进行分组,如果相邻,如图所示:
但是,我似乎无法使用chunk获取元素索引来进行开始
结束
时间比较
答案似乎是这样的:
但是我在写我自己的函数时失败得很惨。(我很难理解slice\u在之前做了什么。)
任何帮助都将不胜感激 这里有一种使用and的方法。不过,它需要Ruby 2.2+
require 'time' # for sorting times
a = [{ name: "joe", start: "9am", end: "10am" },
{ name: "joe", start: "10am", end: "11am" },
{ name: "harry", start: "11am", end: "12pm" },
{ name: "harry", start: "12pm", end: "1pm" },
{ name: "harry", start: "2pm", end: "3pm" },
{ name: "joe", start: "3pm", end: "4pm" },
{ name: "joe", start: "4pm", end: "5pm" }]
a.sort_by { |h| [ h[:name], Time.parse(h[:start]) ] } # 1
.slice_when { |x, y| x[:end] != y[:start] || x[:name] != y[:name] }.to_a # 2
产生
=> [[{:name=>"harry", :start=>"11am", :end=>"12pm"}, {:name=>"harry", :start=>"12pm", :end=>"1pm"}],
[{:name=>"harry", :start=>"2pm", :end=>"3pm"}],
[{:name=>"joe", :start=>"9am", :end=>"10am"}, {:name=>"joe", :start=>"10am", :end=>"11am"}],
[{:name=>"joe", :start=>"3pm", :end=>"4pm"}, {:name=>"joe", :start=>"4pm", :end=>"5pm"}]]
以下是一个带有中间结果的逐步解释:
1) 在名称中按名称和时间对哈希进行排序。请注意使用Time.parse
将时间字符串临时转换为Time
对象以进行适当排序:
=> [{:name=>"harry", :start=>"11am", :end=>"12pm"},
{:name=>"harry", :start=>"12pm", :end=>"1pm"},
{:name=>"harry", :start=>"2pm", :end=>"3pm"},
{:name=>"joe", :start=>"9am", :end=>"10am"},
{:name=>"joe", :start=>"10am", :end=>"11am"},
{:name=>"joe", :start=>"3pm", :end=>"4pm"},
{:name=>"joe", :start=>"4pm", :end=>"5pm"}]
2) 现在,使用Daniel Polfer的解决方案,当前者的结束时间不等于后者的开始时间或名称不匹配时,切片这个中间数组。这将返回一个枚举器
对象,因此最后的方法调用:
=> [[{:name=>"harry", :start=>"11am", :end=>"12pm"}, {:name=>"harry", :start=>"12pm", :end=>"1pm"}],
[{:name=>"harry", :start=>"2pm", :end=>"3pm"}],
[{:name=>"joe", :start=>"9am", :end=>"10am"}, {:name=>"joe", :start=>"10am", :end=>"11am"}],
[{:name=>"joe", :start=>"3pm", :end=>"4pm"}, {:name=>"joe", :start=>"4pm", :end=>"5pm"}]]
如果您的散列已经预排序,那么Daniel Polfer的解决方案应该可以正常工作。但是,如果您有任何数据的名称和/或开始时间不符合以下顺序:
b = [{:name=>"joe", :start=>"3pm", :end=>"4pm"},
{:name=>"bill", :start=>"2pm", :end=>"3pm"},
{:name=>"joe", :start=>"5pm", :end=>"6pm"},
{:name=>"joe", :start=>"4pm", :end=>"5pm"}]
当
返回时,只需使用slice\u
=> [[{:name=>"joe", :start=>"3pm", :end=>"4pm"}],
[{:name=>"bill", :start=>"2pm", :end=>"3pm"}],
[{:name=>"joe", :start=>"5pm", :end=>"6pm"}],
[{:name=>"joe", :start=>"4pm", :end=>"5pm"}]]
而不是
=> [[{:name=>"bill", :start=>"2pm", :end=>"3pm"}],
[{:name=>"joe", :start=>"3pm", :end=>"4pm"},
{:name=>"joe", :start=>"4pm", :end=>"5pm"},
{:name=>"joe", :start=>"5pm", :end=>"6pm"}]]
这里有一种使用和的方法。不过,它需要Ruby 2.2+
require 'time' # for sorting times
a = [{ name: "joe", start: "9am", end: "10am" },
{ name: "joe", start: "10am", end: "11am" },
{ name: "harry", start: "11am", end: "12pm" },
{ name: "harry", start: "12pm", end: "1pm" },
{ name: "harry", start: "2pm", end: "3pm" },
{ name: "joe", start: "3pm", end: "4pm" },
{ name: "joe", start: "4pm", end: "5pm" }]
a.sort_by { |h| [ h[:name], Time.parse(h[:start]) ] } # 1
.slice_when { |x, y| x[:end] != y[:start] || x[:name] != y[:name] }.to_a # 2
产生
=> [[{:name=>"harry", :start=>"11am", :end=>"12pm"}, {:name=>"harry", :start=>"12pm", :end=>"1pm"}],
[{:name=>"harry", :start=>"2pm", :end=>"3pm"}],
[{:name=>"joe", :start=>"9am", :end=>"10am"}, {:name=>"joe", :start=>"10am", :end=>"11am"}],
[{:name=>"joe", :start=>"3pm", :end=>"4pm"}, {:name=>"joe", :start=>"4pm", :end=>"5pm"}]]
以下是一个带有中间结果的逐步解释:
1) 在名称中按名称和时间对哈希进行排序。请注意使用Time.parse
将时间字符串临时转换为Time
对象以进行适当排序:
=> [{:name=>"harry", :start=>"11am", :end=>"12pm"},
{:name=>"harry", :start=>"12pm", :end=>"1pm"},
{:name=>"harry", :start=>"2pm", :end=>"3pm"},
{:name=>"joe", :start=>"9am", :end=>"10am"},
{:name=>"joe", :start=>"10am", :end=>"11am"},
{:name=>"joe", :start=>"3pm", :end=>"4pm"},
{:name=>"joe", :start=>"4pm", :end=>"5pm"}]
2) 现在,使用Daniel Polfer的解决方案,当前者的结束时间不等于后者的开始时间或名称不匹配时,切片这个中间数组。这将返回一个枚举器
对象,因此最后的方法调用:
=> [[{:name=>"harry", :start=>"11am", :end=>"12pm"}, {:name=>"harry", :start=>"12pm", :end=>"1pm"}],
[{:name=>"harry", :start=>"2pm", :end=>"3pm"}],
[{:name=>"joe", :start=>"9am", :end=>"10am"}, {:name=>"joe", :start=>"10am", :end=>"11am"}],
[{:name=>"joe", :start=>"3pm", :end=>"4pm"}, {:name=>"joe", :start=>"4pm", :end=>"5pm"}]]
如果您的散列已经预排序,那么Daniel Polfer的解决方案应该可以正常工作。但是,如果您有任何数据的名称和/或开始时间不符合以下顺序:
b = [{:name=>"joe", :start=>"3pm", :end=>"4pm"},
{:name=>"bill", :start=>"2pm", :end=>"3pm"},
{:name=>"joe", :start=>"5pm", :end=>"6pm"},
{:name=>"joe", :start=>"4pm", :end=>"5pm"}]
当
返回时,只需使用slice\u
=> [[{:name=>"joe", :start=>"3pm", :end=>"4pm"}],
[{:name=>"bill", :start=>"2pm", :end=>"3pm"}],
[{:name=>"joe", :start=>"5pm", :end=>"6pm"}],
[{:name=>"joe", :start=>"4pm", :end=>"5pm"}]]
而不是
=> [[{:name=>"bill", :start=>"2pm", :end=>"3pm"}],
[{:name=>"joe", :start=>"3pm", :end=>"4pm"},
{:name=>"joe", :start=>"4pm", :end=>"5pm"},
{:name=>"joe", :start=>"5pm", :end=>"6pm"}]]
详细,但按您呈现的顺序给出结果,并使用较旧版本的Ruby
a.inject([]) do |result,hash|
if (!result.empty? &&
(result.last.last[:name] == hash[:name]) &&
(result.last.last[:end] == hash[:start]))
result.last << hash
else
result << [hash]
end
result
end
a.inject([])do | result,hash |
如果(!result.empty?&&
(result.last.last[:name]==散列[:name])&&
(result.last.last[:end]==散列[:start]))
result.lastVerbose,但按您呈现的顺序给出结果,并与旧版本的Ruby一起使用
a.inject([]) do |result,hash|
if (!result.empty? &&
(result.last.last[:name] == hash[:name]) &&
(result.last.last[:end] == hash[:start]))
result.last << hash
else
result << [hash]
end
result
end
a.inject([])do | result,hash |
如果(!result.empty?&&
(result.last.last[:name]==散列[:name])&&
(result.last.last[:end]==散列[:start]))
结果:最后一次使用切片前:
y=a[0]
a.slice_before { |hash| x=y
y = hash
x[:name] != y[:name] || x[:end] != y[:start]
}.to_a
使用slice_之前:
y=a[0]
a.slice_before { |hash| x=y
y = hash
x[:name] != y[:name] || x[:end] != y[:start]
}.to_a
那么你想为同一个人分组相邻时间?最多两次吗?或者可能有很多?没有最大值,可能有很多。你的意思是在一个组中有很多?是的,很多连续的时间段。你想为同一个人分组相邻的时间吗?最大值是两个吗?或者可能有很多?没有最大值,可能有很多。你是说一组中有很多?是的,很多连续的时间周期!真是一种享受!不过ruby 2.2版本更干净一些。a.slice_当{h1,h2 |(h1[:name]!=h2[:name])|(h1[:end]!=h2[:start])时。to_a利用了2.2的另一个答案,但为了相同的结果将其减少了一点。只是在适当的地方切片。哦,这是一个非常简单的方法@丹尼尔波尔弗:很好!你应该把它加到你的答案里。那比我的简单多了!美好的真是一种享受!不过ruby 2.2版本更干净一些。a.slice_当{h1,h2 |(h1[:name]!=h2[:name])|(h1[:end]!=h2[:start])时。to_a利用了2.2的另一个答案,但为了相同的结果将其减少了一点。只是在适当的地方切片。哦,这是一个非常简单的方法@丹尼尔波尔弗:很好!你应该把它加到你的答案里。那比我的简单多了!我追求的是名字上的连续跑步。这是步骤4的结果。谢谢你的解释!丹尼尔波尔弗的答案似乎很简单<当{h1,h2 |(h1[:name]!=h2[:name])| |(h1[:end]!=h2[:start])时,代码>切分。有什么不去的理由吗?我不认为有什么理由不去@RyanKing。这比我的有了很大的进步。@RyanKing丹尼尔的回答有一个小问题,我在上面提到了。尽管如此,我还是认为他的方法更好。因此,只要比Daniels的答案先按start
对数据进行排序,就可以了,对吧?我要的是按名称连续运行。这是步骤4的结果。谢谢你的解释!丹尼尔波尔弗的答案似乎很简单<当{h1,h2 |(h1[:name]!=h2[:name])| |(h1[:end]!=h2[:start])时,代码>切分。有什么不去的理由吗?我不认为有什么理由不去@RyanKing。这比我的有了很大的进步。@RyanKing丹尼尔的回答有一个小问题,我在上面提到了。尽管如此,我仍然认为他的方法更好。因此,只要比Daniels的答案先按start
对数据进行排序,就可以了,对吗?