Манипулирование массивом (суммирование одного столбца определенной группой, оставление других одинаковыми) - PullRequest
2 голосов
/ 01 февраля 2011

У меня есть таблица журналов со столбцами name, duration, type, ref_id.

Я обновляю таблицу так часто, что, возможно, она будет выглядеть как столбец ['bill', 'bob', 'bob', 'jill'] для имен, [3, 5, 6, 2] для продолжительности, ['man', boy', 'boy', 'girl'] для типа и [1, 2, 2, 3] для ref_id.

Я хотел бы манипулировать таблицей, чтобы я мог добавить все длительности, чтобы получить хэш или что-то похожее на это:

{'name' => ['bill', 'bob', 'jill'], 'duration' => [3, 11, 2], 'type' => ['man', 'boy', 'girl'], ref_id => [1, 2, 3]}

Как я могу это сделать?

(для получения дополнительной информации - в настоящее время я делаю Log.sum(:duration, :group => 'name'), который дает мне сами имена в качестве ключей (bill, bob, jill) вместо имени столбца, с правильными суммами длительности в качестве их значений (3, 11, 2). Но тогда я теряю остальные данные ...)

Полагаю, я мог бы вручную просмотреть каждый журнал и добавить имя / тип / ref_id, если его нет в хэше, а затем добавить к продолжительности. Если так, то какой лучший способ сделать это?

Если вам известны хорошие источники по манипулированию массивами рельсов / часто используемым идиомам, это тоже было бы здорово!

Ответы [ 3 ]

2 голосов
/ 01 февраля 2011

Сначала пара заметок.

Ваша таблица не нормализована должным образом.Вы должны разбить эту таблицу на (как минимум) две: users и durations.Это следует делать по многим причинам, это реляционные базы данных 101.

Кроме того, требуемый хеш-код в результате также выглядит неправильно, он предполагает, что вы предварительно группируете данные в соответствии с вашей презентацией.Обычно более логично поместить эти результаты в массив хешей, чем в хеш массивов.

Теперь ответим на вопрос:

С вашей таблицей вы можете просто выполнить GROUP BY:

SELECT name, type, ref_id, SUM(duration) as duration
FROM logs
GROUP BY name, type, ref_id

или, используя AR:

durations = Log.find(:all,
  :select => 'name, type, ref_id, SUM(duration) as duration',
  :group => 'name, type, ref_id'
)

Чтобы преобразовать это в хэш массивов, вы должны использовать что-то вроде:

Hash[
  %w{name, type, ref_id, duration}.map{|f|
    [f, durations.map{|h|
      h.attributes[f]
    }]
  }
]
1 голос
/ 01 февраля 2011

Может быть, все, что вам нужно, это что-то вроде этого, который просматривает все записи журнала и собирает результаты:

# Define attributes we're interested in
operate_on = %w[ name duration type ref_id ]

# Create a new hash with placeholder hashes to collect instances
summary = Hash[operate_on.map { |k| [ k, { } ] }]

Log.all.collect do |log|
  operate_on.each do |attr|
    # Flag this attribute/value pair as having been seen
    summary[attr][log.send(attr)] = true
  end
end

# Extract only the keys, return these as a hash
summary = Hash[summary.map { |key, value| [ key, value.keys ] }]

Более эффективным методом было бы сделать это как несколько вызовов SELECT DISTINCT(x) вместо создания множества моделей.

0 голосов
/ 01 февраля 2011

Не совсем понял, хотите ли вы сохранить записи из своего хэша или хотите запросить таблицу и получить результаты обратно в этой форме.Если вы хотите вернуть хеш, то это должно сработать:

Log.all.inject({}) do |hash, l|
  hash['name'] ||= []
  hash['duration'] ||= []
  hash['type'] ||= []
  hash['ref_id'] ||= []
  hash['name'] << l.name
  hash['duration'] << l.duration
  hash['type'] << l.type
  hash['ref_id'] << l.ref_id
  hash
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...