我有一组task,其中一个任务可以通过runs_with字段链接到另一个任务,如下所示。
<Task id: 'abc', name: 'paint the fance', progressive: 1, runs_with: nil>
<Task id: 'def', name: 'mow the lawn', progressive: 2, runs_with: 1>
<Task id: 'ghi', name: 'wash the dishes', progressive: 3, runs_with: nil>
<Task id: 'xyz', name: 'take out the trash', progressive: 4, runs_with: 3>
<Task id: 'qur', name: 'wash the car', progressive: 5, runs_with: 2>
<Task id: 'gbj', name: 'walk the dog', progressive: 6, runs_with: 3>现在,我需要对它们进行分组,这样所有的链接都在一个组(一个数组)中结束。
[[<Task id: 'abc', name: 'paint the fance', progressive: 1, runs_with: nil>,
<Task id: 'def', name: 'mow the lawn', progressive: 2, runs_with: 1>,
<Task id: 'qur', name: 'wash the car', progressive: 5, runs_with: 2>],
[<Task id: 'ghi', name: 'wash the dishes', progressive: 3, runs_with: nil>,
<Task id: 'xyz', name: 'take out the trash', progressive: 4, runs_with: 3>,
<Task id: 'gbj', name: 'walk the dog', progressive: 6, runs_with: 3>]]我最初的想法是
runs_with上的分区。task创建一个组。task,并将它们附加到组中,包括链接的task。想知道是否有更多的习惯方式来分组他们。
发布于 2020-02-18 10:54:18
我会这样处理它。给定一个Task类和一个任务数组:
class Task
ATTRIBUTES = [:id, :name, :progressive, :runs_with]
attr_accessor *ATTRIBUTES
include ActiveModel::Model
def inspect
'<Task %s>' % ATTRIBUTES.map { |a| '%s: %s' % [a, send(a).inspect] }.join(', ')
end
end
tasks = [
Task.new(id: 'abc', name: 'paint the fance', progressive: 1, runs_with: nil),
Task.new(id: 'def', name: 'mow the lawn', progressive: 2, runs_with: 1),
Task.new(id: 'ghi', name: 'wash the dishes', progressive: 3, runs_with: nil),
Task.new(id: 'xyz', name: 'take out the trash', progressive: 4, runs_with: 3),
Task.new(id: 'qur', name: 'wash the car', progressive: 5, runs_with: 2),
Task.new(id: 'gbj', name: 'walk the dog', progressive: 6, runs_with: 3)
]我将创建一个散列,其中每个值都是封装在数组中的任务,其编号作为键:
hash = tasks.group_by(&:progressive)
{
1 => [<Task id: "abc", name: "paint the fance", progressive: 1, runs_with: nil>],
2 => [<Task id: "def", name: "mow the lawn", progressive: 2, runs_with: 1>],
3 => [<Task id: "ghi", name: "wash the dishes", progressive: 3, runs_with: nil>],
4 => [<Task id: "xyz", name: "take out the trash", progressive: 4, runs_with: 3>],
5 => [<Task id: "qur", name: "wash the car", progressive: 5, runs_with: 2>],
6 => [<Task id: "gbj", name: "walk the dog", progressive: 6, runs_with: 3>]
}然后遍历原始的tasks数组,对于每个具有runs_with属性的任务,将任务的数组与相应任务的数组合并为一个:
tasks.each do |task|
if task.runs_with
hash[task.runs_with].concat(hash[task.progressive])
hash[task.progressive] = hash[task.runs_with]
end
end这将有效地合并数组并减少数组的数量。然而,哈希将引用来自不同键的(相同)数组,因此最后我们必须获取哈希的唯一值:
hash.values.uniq
#=> [[<Task id: "abc", name: "paint the fance", progressive: 1, runs_with: nil>,
# <Task id: "def", name: "mow the lawn", progressive: 2, runs_with: 1>,
# <Task id: "qur", name: "wash the car", progressive: 5, runs_with: 2>],
# [<Task id: "ghi", name: "wash the dishes", progressive: 3, runs_with: nil>,
# <Task id: "xyz", name: "take out the trash", progressive: 4, runs_with: 3>,
# <Task id: "gbj", name: "walk the dog", progressive: 6, runs_with: 3>]]发布于 2020-02-18 10:11:13
我认为
tasks.group_by(&:runs_with).values应该这么做。
基本上,groups_by方法将创建一个哈希,其中runs_with值是键,而值是包含该runs_with值的所有任务的数组。然后简单地调用哈希上的values来获取所有值的数组。
发布于 2021-01-13 21:42:14
假设:
tasks = [
{ Task id: 'abc', progressive: 1, runs_with: nil },
{ Task id: 'def', progressive: 2, runs_with: 1 },
{ Task id: 'ghi', progressive: 3, runs_with: nil },
{ Task id: 'xyz', progressive: 4, runs_with: 3 },
{ Task id: 'qur', progressive: 5, runs_with: 2 },
{ Task id: 'gbj', progressive: 6, runs_with: 3 }
]实际上也是同样的问题。
您可以首先按以下方式对数组进行分区:
heads, tails = tasks.partition { |h| h[:runs_with].nil? }
#=> [[{:Task_id=>"abc", :progressive=>1, :runs_with=>nil},
# {:Task_id=>"ghi", :progressive=>3, :runs_with=>nil}],
# [{:Task_id=>"def", :progressive=>2, :runs_with=>1},
# {:Task_id=>"xyz", :progressive=>4, :runs_with=>3},
# {:Task_id=>"qur", :progressive=>5, :runs_with=>2},
# {:Task_id=>"gbj", :progressive=>6, :runs_with=>3}]]所以
heads
#=> [{:Task_id=>"abc", :progressive=>1, :runs_with=>nil},
# {:Task_id=>"ghi", :progressive=>3, :runs_with=>nil}]
tails
#=> [{:Task_id=>"def", :progressive=>2, :runs_with=>1},
# {:Task_id=>"xyz", :progressive=>4, :runs_with=>3},
# {:Task_id=>"qur", :progressive=>5, :runs_with=>2},
# {:Task_id=>"gbj", :progressive=>6, :runs_with=>3}]接下来,定义数组数组,在将散列附加到其元素后,将返回该数组:
head_groups = heads.map { |head| [head] }
#=>[[{:Task_id=>"abc", :progressive=>1, :runs_with=>nil}],
# [{:Task_id=>"ghi", :progressive=>3, :runs_with=>nil}]]我们需要跟踪:progressive对于head_groups的每个元素(一个数组)的最后一个元素(一个哈希)的值:
curr_progressive = heads.each_index.with_object({}) {|i,h| h[heads[i] [:progressive]] = i}
#=> {1=>0, 3=>1}现在按tail[:runs_with]排序尾巴
sorted_tails = tails.sort_by { |tail| tail[:runs_with] }
#=> [{:Task_id=>"def", :progressive=>2, :runs_with=>1},
# {:Task_id=>"qur", :progressive=>5, :runs_with=>2},
# {:Task_id=>"xyz", :progressive=>4, :runs_with=>3},
# {:Task_id=>"gbj", :progressive=>6, :runs_with=>3}]我们现在只需要将sorted_tails中的每一个散列追加到head_groups的适当元素(数组)中。
sorted_tails.each_with_object(head_groups) do |tail, head_groups|
head_group = curr_progressive[tail[:runs_with]]
head_groups[head_group] << tail
curr_progressive[tail[:progressive]] = head_group
end
#=>[[{:Task_id=>"abc", :progressive=>1, :runs_with=>nil},
# {:Task_id=>"def", :progressive=>2, :runs_with=>1},
# {:Task_id=>"qur", :progressive=>5, :runs_with=>2}],
# [{:Task_id=>"ghi", :progressive=>3, :runs_with=>nil},
# {:Task_id=>"xyz", :progressive=>4, :runs_with=>3},
# {:Task_id=>"gbj", :progressive=>6, :runs_with=>3}]]当然,我们可以在一定程度上简化这些步骤。在计算heads、tails和curr_progressive之后,我们可以编写以下内容:
tails.sort_by { |tail| tail[:runs_with] }
.each_with_object(heads.map { |head| [head] }) do |tail, head_groups|
head_group = curr_progressive[tail[:runs_with]]
head_groups[head_group] << tail
curr_progressive[tail[:progressive]] = head_group
end我想提到的是,在准备这个答案时,我(第一次)使用了一个带有Jupyter笔记本的安装Rubyv2.7.1来编写和测试代码。Jupyter笔记本电脑在运行Python代码方面很受欢迎,但它们也可以与许多其他语言一起使用。这里是它们在Ruby中使用的一个例子。我被打动了。
https://stackoverflow.com/questions/60278290
复制相似问题