def count_em(str, who)
str.gsub(/\b(?:#{who.join('|')})\b/i).
each_with_object(Hash.new(0)) { |person,h| h[person] += 1 }
end
str = "Monday Tina will meet Sally and Harris. Then Tina will visit her " +
"mom Marina. Marina and Tina will meet David for dinner. Sally will " +
"then take Tina out for a late night party."
who = %w| Sally Marina Tina |
count_em(str, who)
#> {"Tina"=>4, "Sally"=>2, "Marina"=>2}
Первые шаги следующие:
r = /\b(?:#{who.join('|')})\b/i
#=> /\b(?:Sally|Marina|Tina)\b/i
enum = str.gsub(r)
#=> #<Enumerator: "Monday Tina will meet Sally and Harris. Then
# ...
# for a late night party.":gsub(/\b(?:Sally|Marina|Tina)\b/i)>
Мы можем преобразовать это в массив, чтобы увидеть значения, которые будут переданы в each_with_object
.
enum.to_a
#=> ["Tina", "Sally", "Tina", "Marina", "Marina", "Tina", "Sally", "Tina"]
Затем мы просто подсчитываем количество экземпляров уникальных значений, сгенерированных enum
.
enum.each_with_object(Hash.new(0)) { |person,h| h[person] += 1 }
#=> {"Tina"=>4, "Sally"=>2, "Marina"=>2}
См. String # gsub , в частности, когда есть один аргумент и нетблок.По общему признанию это необычное использование gsub
, поскольку оно не делает подстановок, но здесь я предпочитаю это String#scan
, потому что gsub
возвращает перечислитель, тогда как сканирование создает временный массив.
См. Также Hash :: new , случай, когда new
принимает аргумент, а не блок.Аргумент называется значением по умолчанию .Если h
является таким хэшем, значение по умолчанию возвращается h[k]
, если h
не имеет ключа k
.Хэш не изменяется.
Здесь значение по умолчанию равно нулю.Когда выражение h[person] += 1
анализируется, оно преобразуется в:
h[person] = h[person] + 1
Если person
равно "Tina"
, и это первый раз, когда "Tina"
генерируется перечислителем и передается вblock, h
не будет иметь ключа "Tina"
, поэтому выражение становится:
h["Tina"] = 0 + 1
, поскольку 0
является значением по умолчанию.В следующий раз, когда "Tina"
передается в блок, хэш имеет ключ "Tina"
(со значением 1
), поэтому выполняется следующий расчет.
h["Tina"] = h["Tina"] + 1 #=> 1 + 1 #=> 2