Я рассматриваю разницу между этими методами в рубине. Я знаю, что select возвращает массив элементов, а detect возвращает только один и первый согласованный элемент. Но есть ли разница, если я наберу array.select{ condition }[0]? Он вернет первую единицу, например detect. Например:

a = [2,3,4,5]
a.detect{|k| k.even? }
# => 2
a.select{|k| k.even? }[0]
# => 2

Кто-нибудь может объяснить мне другие различия между этими методами и привести несколько примеров, когда {{X 0}} будет лучше, чем select?

1
Bartłomiej Gładys 8 Сен 2016 в 18:00

3 ответа

Лучший ответ

Когда вам нужно получить только один элемент, предпочтительнее использовать detect, потому что он прекратит итерацию по массиву, когда найдет первое вхождение, соответствующее условию. Поскольку select извлекает все вхождения, которые соответствуют условию, он должен перебирать весь список. В худшем случае (когда элемент, соответствующий условию, отсутствует в списке), они эквивалентны, но если элемент, который вы ищете, находится в начале списка, detect будет более эффективным.

4
Matt 8 Сен 2016 в 15:03

Разница в том, что detect вернет первое значение, которое блок оценивает как истинное, в данном случае это число 2. Это быстрее, если вам нужно только одно значение из массива, потому что он не будет оценивать остальную часть массива после нахождения одного значения, которое возвращает true.

select вернет каждый элемент, который возвращает true в зависимости от блока, поэтому он вернет [2,4]. select будет оценивать блок для каждого элемента, поэтому он медленнее, чем detect.

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

Хорошей иллюстрацией этого будет, скажем, у вас есть массив из 10 миллионов элементов, в которых случайные числа от 0 до 1 миллиона.

arr = Array.new(1_000_000) { rand(1_000_000) }

Если вы просто хотите вернуть первое четное число, использование detect в этом значении будет значительно быстрее, чем select. Вот контрольные измерения для detect и select.

detect:  0.000000   0.000000   0.000000 (  0.000010)
select:  0.740000   0.010000   0.750000 (  0.753949)
1
davidhu 8 Сен 2016 в 15:12

Я бы разместил здесь пример, который ИМХО все проясняет:

(1..Float::INFINITY).detect &:odd?
#⇒ 1
(1..Float::INFINITY).select(&:odd?).first
#⇒ :(
4
Aleksei Matiushkin 8 Сен 2016 в 15:11