Все ответы до сих пор пересекают все a
один раз (@ Stefan's) или пересекают все или часть a
b.size
раз.Мой ответ проходит часть или все из a
один раз.Это относительно эффективно, когда a
велико, b
мало по отношению к a
и все элементы в b
появляются в a
.
Мое решение особенно эффективно, когда a
упорядочено таким образом, что элементы b
обычно появляются в начале a
.Например, a
может быть списком фамилий, отсортированных по убыванию частоты встречаемости среди населения в целом (например, ['smith', 'jones',...]
), а b
- это список имен, которые нужно искать в a
.
a
и b
могут содержать дубликаты 1 , и не все элементы b
гарантированно находятся в a
.Я предполагаю, что b
не является пустым.
Код
require 'set'
def lookup_index(a, b)
b_set = b.to_set
b_hash = {}
a.each_with_index do |n,i|
next unless b_set.include?(n)
b_hash[n] = i
b_set.delete(n)
break if b_set.empty?
end
b_hash.values_at(*b)
end
Я преобразовал b
в набор, чтобы сделать поиск сопоставимым по скорости с поиском по хешу (которыйне должно быть ничего удивительного, учитывая, что наборы реализованы с базовым хешем).Конечно, хеш-поиск выполняется очень быстро.
Примеры
a = [1,2,3,4,5,6,7,8,9,10,8]
b = [3,5,8,10,11,5]
Обратите внимание, что в этом примере a
и b
содержат дубликаты, а 11
в b
отсутствует в a
.
lookup_index(a, b)
#=> [2, 4, 7, 9, nil, 4]
Обратите внимание, что возвращаемый массив содержит индекс 4
дважды, один раз для каждого 5
в b
.Кроме того, массив содержит nil
в индексе 4
, чтобы показать, что это b[4] #=> 11
, который не появляется в a
.Без заполнителя nil
не было бы возможности сопоставить элементы b
с индексами в a
.Однако, если заполнитель nil
нежелателен, можно заменить b_hash.values_at(*b)
на b_hash.values_at(*b).compact
или, если дубликаты нежелательны, на b_hash.values_at(*b).compact.uniq
.
В качестве второго примера предположим, что нам дано следующее.
a = [*1..10_000]
b = 10.times.map { rand(100) }.shuffle
#=> [30, 62, 36, 24, 41, 27, 83, 61, 15, 55]
lookup_index(a, b)
#=> [29, 61, 35, 23, 40, 26, 82, 60, 14, 54]
Здесь решение было найдено после перечисления первых 83
элементов a
.
1 Мое решение не будет более эффективным, если дубликаты не будут разрешены в a
и / или b
.