Используя Ruby, Как передать коллекцию в метод, но подмножество этого? - PullRequest
0 голосов
/ 20 ноября 2010

У меня есть коллекция пользователей:

users = User.all()

Я хочу передать подмножество пользовательской коллекции методу. Каждое подмножество должно содержать 1000 элементов (или меньше на последней итерации).

some_method(users)

Допустим, у пользователей 9500 элементов, я хочу вызвать some_method 10 раз, 9 раз передать 1000 элементов и в последний раз 500.

Ответы [ 4 ]

3 голосов
/ 20 ноября 2010

С Rails 2.3 можно указать batch_size:

User.find_in_batches(:batch_size =>1000) do |users|
    some_method(users)
end

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

3 голосов
/ 20 ноября 2010

Вы можете использовать Enumerable#each_slice метод:

User.all.each_slice(1000) do |subarray|
  some_method subarray
end

, но это сначала вытянет все записи из базы данных.

Однако, я думаю, вы могли бысделайте что-то вроде этого:

def ar_each_slice scope, size
  (scope.count.to_f / size).ceil.times do |i|
    yield scope.scoped(:offset => i*size, :limit => size)
  end
end

и используйте его следующим образом:

ar_each_slice(User.scoped, 1000) do |slice|
  some_method slice.all
end

Сначала он получит количество записей (используя COUNT), а затем получит 1000 на 1000 с помощью LIMITи передать его в свой блок.

0 голосов
/ 20 ноября 2010

Я забыл об использовании :batch_size, но Чандра предложил это. Это правильный путь.


Использование .all попросит базу данных извлечь все записи, передав их в Ruby для хранения, а затем перебрать их внутри. Это действительно плохой способ справиться с этим, если ваша база данных будет расти. Это связано с тем, что глобус записей будет усложнять работу DBM по мере роста, и Ruby придется выделять все больше и больше места для их хранения. В результате ваше время отклика будет расти.

Лучшее решение состоит в том, чтобы использовать опции :limit и :offset, чтобы указать DBM последовательно находить первые 1000 записей со смещением 0, затем следующие 1000 записей со смещением 1 и т. Д. больше записей.

Вы можете определить, сколько раз вам придется зацикливаться, выполнив .count перед тем, как начать спрашивать, что действительно быстро, если ваше предложение where не является чудовищным, или просто зацикливаться, пока не получите никаких записей назад.

0 голосов
/ 20 ноября 2010

Я думаю, вы должны разделить на подмножество вручную. Например,

some_method(users[0..999])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...