首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将集合与相关对象分组

将集合与相关对象分组
EN

Stack Overflow用户
提问于 2020-02-18 10:04:31
回答 3查看 59关注 0票数 2

我有一组task,其中一个任务可以通过runs_with字段链接到另一个任务,如下所示。

代码语言:javascript
复制
<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>

现在,我需要对它们进行分组,这样所有的链接都在一个组(一个数组)中结束。

代码语言:javascript
复制
[[<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

想知道是否有更多的习惯方式来分组他们。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-02-18 10:54:18

我会这样处理它。给定一个Task类和一个任务数组:

代码语言:javascript
复制
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)
]

我将创建一个散列,其中每个值都是封装在数组中的任务,其编号作为键:

代码语言:javascript
复制
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属性的任务,将任务的数组与相应任务的数组合并为一个:

代码语言:javascript
复制
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

这将有效地合并数组并减少数组的数量。然而,哈希将引用来自不同键的(相同)数组,因此最后我们必须获取哈希的唯一值:

代码语言:javascript
复制
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>]]
票数 3
EN

Stack Overflow用户

发布于 2020-02-18 10:11:13

我认为

代码语言:javascript
复制
tasks.group_by(&:runs_with).values

应该这么做。

基本上,groups_by方法将创建一个哈希,其中runs_with值是键,而值是包含该runs_with值的所有任务的数组。然后简单地调用哈希上的values来获取所有值的数组。

票数 0
EN

Stack Overflow用户

发布于 2021-01-13 21:42:14

假设:

代码语言:javascript
复制
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 }
]

实际上也是同样的问题。

您可以首先按以下方式对数组进行分区:

代码语言:javascript
复制
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}]]

所以

代码语言:javascript
复制
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}]

接下来,定义数组数组,在将散列附加到其元素后,将返回该数组:

代码语言:javascript
复制
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的每个元素(一个数组)的最后一个元素(一个哈希)的值:

代码语言:javascript
复制
curr_progressive = heads.each_index.with_object({}) {|i,h| h[heads[i] [:progressive]] = i}
  #=> {1=>0, 3=>1}

现在按tail[:runs_with]排序尾巴

代码语言:javascript
复制
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的适当元素(数组)中。

代码语言:javascript
复制
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}]]

当然,我们可以在一定程度上简化这些步骤。在计算headstailscurr_progressive之后,我们可以编写以下内容:

代码语言:javascript
复制
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中使用的一个例子。我被打动了。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60278290

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档