Группировка коллекции со связанными объектами - PullRequest
2 голосов
/ 18 февраля 2020

У меня есть группа task s, где задача может быть связана с другой через поле 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, который может работать в одиночку.
  • l oop через другие task s и добавить их в группу, включая связанные task.

Интересно, есть ли еще идиоматические c способ их группировки.

Ответы [ 2 ]

2 голосов
/ 18 февраля 2020

Вот как бы я подошел к этому. Учитывая класс 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)
]

Я бы создал ха sh, где каждое значение было бы задачей, заключенной в массив с номером в качестве ключа:

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

Это будет эффективно объединять массивы и сокращать количество массивов по пути. Однако ha sh будет ссылаться на эти (идентичные) массивы из разных ключей, поэтому в конце мы должны получить уникальные значения ha sh * *1014*:

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>]]
0 голосов
/ 18 февраля 2020

Я думаю

tasks.group_by(&:runs_with).values

должно это сделать.

По существу, метод groups_by создаст ха sh, где значением параметра значение_по_замне является ключ, а значением является массив всех задач с этим значением_перехода. Затем вы просто вызываете values на ha sh, чтобы получить массив всех значений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...