Зацикливание нескольких массивов - PullRequest
1 голос
/ 21 февраля 2020

У меня есть массив, содержащий несколько массивов (число может варьироваться) значимых измерений (массив может содержать до 150 объектов).

С помощью массива мне нужно найти комбинацию (один элемент для каждый подмассив), который соответствует условию.

Из-за размеров я попытался использовать Enumerator::Lazy следующим образом

catch :match do
   array[0].product(*array[1..-1]).lazy.each do |combination|
    throw :match if ConditionMatcher.match(combination)
  end
end

Однако я понимаю, когда я вызываю each Перечислитель оценивается и работает очень медленно. Я попытался заменить each методами, включенными в Enumerator::Lazy, такими как take_while

 array[0].product(*array[1..-1]).lazy.take_while do |combination|
  return false if ConditionMatcher.match(combination)
 end

Но также в этом случае product оценивается с низкой производительностью.

Для повышения производительности, даже если мне это не очень нравится, я думаю заменить product на вложенный each l oop. Что-то вроде

catch :match do
 array[0].each do |first|
   array[1].each do |second|
     array[2].each do |third|
       throw :match if ConditionMatcher.match([first, second, third])
     end
   end
 end
end

Из-за того, что количество подмассивов время от времени меняется. Я не уверен, как это реализовать.

Кроме того, есть ли лучший способ l oop через все подмассивы без загрузки всего набора комбинаций?

  • Обновление 1 -

Каждый вложенный массив содержит ActiveRecord::Relation в полиморфной c ассоциации. Следовательно, каждый элемент каждой комбинации отвечает на те же 2 метода (start_time и end_time), каждый из которых возвращает экземпляр Time.

Сопоставитель проверяет, все ли объекты в комбинации не имеют перекрывающиеся времена.

1 Ответ

4 голосов
/ 21 февраля 2020

Проблема в том, что Array#product уже возвращает огромный массив, содержащий все комбинации. С 3 подмассивами, содержащими 150 элементов каждый, он возвращает массив 150 × 150 × 150 = 3 375 000 элементов. Вызов lazy для этого массива ничего не ускорит.

Чтобы заставить product вычислять декартово произведение лениво (т.е. одну комбинацию за другой), вам просто нужно (напрямую) передать блок в это:

first, *others = array

first.product(*others) do |combination|
  # ...
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...