select
- метод фильтрации. Он передает каждый элемент в блок, и блок определяет, должен ли этот элемент быть включен в вывод, возвращая true
или false
.
Блок в вашем коде делает это, подсчитывая, как часто этот элемент происходит в массиве. Если это происходит более одного раза, блок возвращает true
, а select
включает в вывод соответствующий элемент.
Это может помочь поставить счетчик x
, x
и Возвращаемое значение блока в таблице:
x | count(x) | count(x) > 1
---+----------+-------------
1 | 3 | true
1 | 3 | true
3 | 2 | true
2 | 1 | false
6 | 2 | true
7 | 1 | false
9 | 2 | true
6 | 2 | true
5 | 1 | false
1 | 3 | true
8 | 1 | false
9 | 2 | true
3 | 2 | true
Ваш select
возвращает все элементы с count
выше 1: (с true
в последнем столбце)
array = [1, 1, 3, 2, 6, 7, 9, 6, 5, 1, 8, 9, 3]
array.select { |x| array.count(x) > 1 }
#=> [1, 1, 3, 6, 9, 6, 1, 9, 3]
uniq
затем избавляется от дубликатов:
array.select { |x| array.count(x) > 1 }.uniq
#=> [1, 3, 6, 9]
Вы могли заметить, что count
должен пройти array
один раз для каждого элемента, чтобы подсчитать его вхождения.
Гораздо быстрее использовать ha sh для подсчета элементов:
counts = Hash.new(0)
array.each { |x| hash[x] += 1 }
counts
#=> {1=>3, 3=>2, 2=>1, 6=>2, 7=>1, 9=>2, 5=>1, 8=>1}
Подсчет вхождений настолько распространен, что Ruby 2.7 имеет специальный метод tally
:
counts = array.tally
#=> {1=>3, 3=>2, 2=>1, 6=>2, 7=>1, 9=>2, 5=>1, 8=>1}
Теперь мы можем просто выбрать ключи со значением выше 1:
counts.select { |k, v| v > 1 }
#=> {1=>3, 3=>2, 6=>2, 9=>2}
counts.select { |k, v| v > 1 }.keys
#=> [1, 3, 6, 9]