Как мне подсчитать несколько уникальных слов в строке Ruby? - PullRequest
0 голосов
/ 21 декабря 2018

Попытка написать код на Ruby, который будет считать уникальные слова и возвращать их общее количество вхождений.

Итак, предположим, я хочу найти число случаев для Салли, Марины и Тины в следующем предложении: «В понедельник Тина встретится с Салли и Харрисом. Затем Тина навестит свою маму Марину. Марина и Тина встретятся с Дэвидом на обеде.«.

Я попробовал следующее, но это побеждает сухого принципала.Есть ли способ лучше?

string = "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." 

puts "Marina appears #{string.split.count("brown").to_i} times."
puts "Tina appears #{string.split.count("grey").to_i} times."
puts "Sally appears #{string.split.count("blue").to_i} times."

Ожидаемый результат: программа просматривает текст на предмет уникальных слов и возвращает их.

Фактически: мне пришлось жестко закодировать каждое уникальное слово в отдельной строке PUTS и выполнить string.split.count (для этого уникального слова)

Примечание: я пробовал следующее, но это дает мне КАЖДОЕ слово.Мне нужно уточнить это, чтобы дать мне только те, о которых я прошу.Вот где я борюсь.

def cw(string)
  w = string.split(' ')
  freq = Hash.new(0)
  w.each { |w| freq[w.downcase] += 1 }
  return freq
end
puts cw(string)

Ответы [ 2 ]

0 голосов
/ 21 декабря 2018
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
0 голосов
/ 21 декабря 2018

Чтобы получить только требуемое имя человека:

people = ['Marina', 'Tina', 'Sally', 'Dory']
tmp = string.scan(/\w+/).keep_if{ |w| people.include? w }
counts people.map{ |name| [name, tmp.count{|n| n == name }] }.to_h
counts #=> {"Marina"=>2, "Tina"=>4, "Sally"=>2, "Dory"=>0}

Это сопоставляет массив peopole с tmp во вложенный массив, содержащий [name, count], затем преобразуется в хеш.

Хорошо, что он возвращает 0, если люди не появляются, см. 'Dory'.


Чтобы получить общий счет, двумя способами:
tmp.size #=> 8
counts.values.sum #=> 8
...