我有一个完整的对象阵列,我想通过将它们与周围元素进行比较来分组。
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" }]]
连续时间段没有最大值。
我可以按name
对其进行分组,如果在此处相邻,则可以将其分组:Ruby / Rails Groups only Adjacent Array Elements
a.chunk { |hash| hash[:name] }.map(&:last)
但它似乎并不像我可以通过chunk获取元素索引来进行start
end
时间比较。
看起来答案就在这里:Grouping an array by comparing 2 adjacent elements
但是我在编写自己的功能时失败了。 (我很难理解slice_before
的作用。)
def self.group_by(data)
tmp = data.first
data.slice_before do |item|
tmp, prev = item, tmp
item.application == prev.application &&
item.start == prev.end
end.to_a
return data
end
任何帮助将不胜感激!
答案 0 :(得分:2)
这是使用Enumerable#sort_by
和Enumerable#slice_when
的单向方式。但它需要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的解决方案时,将此中间数组切片。这将返回Enumerator
个对象,因此最终to_a
方法调用:
=> [[{: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_when
返回
=> [[{: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"}]]
答案 1 :(得分:2)
详细,但按照您呈现的顺序给出结果,并使用旧版本的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
一次构建一个哈希值,选择将哈希值添加到最后一个数组的末尾或者&#34;步骤&#34;到一个新的最终数组条目。
Ruby 2.2 +
a.slice_when{|h1,h2| (h1[:name]!=h2[:name]) || (h1[:end]!=h2[:start])}.to_a
答案 2 :(得分:0)
使用slice_before:
y=a[0]
a.slice_before { |hash| x=y
y = hash
x[:name] != y[:name] || x[:end] != y[:start]
}.to_a