Как поместить sh строку в новый массив в Ruby - PullRequest
1 голос
/ 17 июня 2020

Я хочу найти подстроки в заданной строке. Каждый раз, когда подстрока включается во введенную строку, я добавляю ее в массив. В конечном итоге я хочу tally этого массива, чтобы подсчитать, сколько раз появляется каждая подстрока.

Проблема в том, что подстрока из словаря в моем коде добавляется только один раз к new_array.

Например:

dictionary = ["below", "down","go","going","horn","how","howdy","it","i","low","own","part","partner","sit"]

substrings("go going", dictionary)

Должен выводиться:

{"go"=>2, "going"=>1, "i"=>1}

, но я получаю

{"go"=>1, "going"=>1, "i"=>1}

Это мой код:

def substrings(word, array) 

  new_array = []

  array.each do |index| 

    if word.downcase.include? (index)

      new_array << index

    end
  end

  puts new_array.tally

end

 dictionary = ["below", "down","go","going","horn","how","howdy","it","i","low","own","part","partner","sit"]

 substrings("go going", dictionary)

Ответы [ 7 ]

1 голос
/ 17 июня 2020

В зависимости от размера вашего словаря.

Вы можете просто сопоставить все элементы с их количеством вхождений, если подстрока существует в слове.

dictionary.map {|w| [w,word.scan(w).size] if word.include?(w)}.compact.to_h
0 голосов
/ 18 июня 2020

Я бы начал с этого:

dictionary = %w[down go going it i]
target = 'go going'

dictionary.flat_map { |w|
  target.scan(Regexp.new(w, Regexp::IGNORECASE))
}.reject(&:empty?).tally
# => {"go"=>2, "going"=>1, "i"=>1}
0 голосов
/ 17 июня 2020

Другой вариант - использовать Array # product после разделения слова, поэтому вы можете использовать Enumerable # Tally по своему усмотрению:

word = "go going"
word.split.product(dictionary).select { |a, b| a.include? b }.map(&:last).tally

#=> {"go"=>2, "going"=>1, "i"=>1}

It не выводит то же самое, когда word = "gogoing", поскольку он разделен на один массив элементов. Итак, я не могу сказать, является ли это поведение, которое вы ищете.

0 голосов
/ 17 июня 2020

Если я понимаю, что нам дан массив dictionary слов, не содержащих пробелов, и строку str, и мы должны построить ha sh, ключи которого являются элементами dictionary и чьи значения равны количество неперекрывающихся подстрок 1 из str, для которых ключ является подстрокой. Возвращаемое значение ha sh должно исключать ключи, имеющие нулевые значения.

Этот ответ касается ситуации, когда в:

substrings(str, dictionary)

dictionary велико, str не слишком -large (значение которого я уточню позже) и эффективность важны.

Начнем с определения вспомогательного метода, цель которого станет ясной.

def substr_counts(str)
  str.split.each_with_object(Hash.new(0)) do |word,h|
    (1..word.size).each do |sub_len|
      (0..word.size-sub_len).each do |start_idx|
        h[word[start_idx,sub_len]] += 1
      end
    end
  end
end       

Для примера, приведенного в вопрос,

substr_counts("go going")
  #=> {"g"=>3, "o"=>2, "go"=>2, "i"=>1, "n"=>1, "oi"=>1, "in"=>1, "ng"=>1,
  #    "goi"=>1, "oin"=>1, "ing"=>1, "goin"=>1, "oing"=>1, "going"=>1}

Как видно, этот метод разбивает str на слова, вычисляет каждую подстроку каждого слова и возвращает ha sh, чьи ключи являются подстроками, а значениями - общее количество неперекрывающиеся подстроки во всех словах, содержащих эту подстроку.

Требуемый ha sh теперь можно построить быстро.

def cover_count(str, dictionary)
  h = substr_counts(str)
  dictionary.each_with_object({}) do |word,g|
    g[word] = h[word] if h.key?(word)
  end
end

dictionary = ["below", "down", "go", "going", "horn", "how", "howdy", 
              "it", "i", "low", "own", "part", "partner", "sit"]

cover_count("go going", dictionary)
  #=> {"go"=>2, "going"=>1, "i"=>1}

Другой пример:

str = "lowner partnership lownliest"
cover_count(str, dictionary)
  #=> {"i"=>2, "low"=>2, "own"=>2, "part"=>1, "partner"=>1}     

Здесь

substr_counts(str)
  #=> {"l"=>3, "o"=>2, "w"=>2, "n"=>3, "e"=>3, "r"=>3, "lo"=>2,
  #    ...
  #    "wnliest"=>1, "lownlies"=>1, "ownliest"=>1, "lownliest"=>1} 
substr_counts(str).size
  #=> 109

Здесь есть очевидный компромисс . Если str является длинным, и особенно если он содержит длинные слова 2 , построение h займет слишком много времени, чтобы оправдать экономию за счет отсутствия определения, для каждого слова в dictionary, если это слово содержится в каждом слове str. Однако, если стоит построить h, общая экономия времени может быть значительной.

1. Под «неперекрывающимися» я подразумеваю, что если str равно 'bobobo', оно содержит одну, а не две подстроки 'bobo'.

2. substr_counts("antidisestablishmentarianism").size #=> 385, неплохо.

0 голосов
/ 17 июня 2020

Вы должны подсчитать, сколько раз строка появляется в индексе, поэтому используйте scan:

def substrings(word, array) 

  hash = {}

  array.each do |index| 
    if word.downcase.include? (index)
      new_hash = {index => word.scan(/#{index}/).length}; 
      hash.merge!(new_hash) 
    end
  end

  puts hash 

end
0 голосов
/ 17 июня 2020

Только слова "go", "going" и "i" из вашего словаря являются подстроками вашей фразы. Каждое из этих слов встречается в словаре только один раз. Итак, new_array содержит ["go", "going", "i"], что точно {"go"=>1, "going"=>1, "i"=>1}.

Я предполагаю, что вы ожидали, что go будет дважды, потому что это дважды в вашей фразе. В этом случае вы можете изменить свой метод на

def substrings(word, array) 
  new_array = []
  array.each do |index| 
    word.scan(/#{index}/).each { new_array << index }
  end
  puts new_array.tally
end

word.scan(/#{index}/) возвращает каждое вхождение подстроки в вашей фразе.

0 голосов
/ 17 июня 2020

Вы можете использовать сканирование , чтобы подсчитать, сколько раз появляется каждая подстрока.

def substrings(word, array)
  output = {}
  array.each do |index|
     count_substring_appears = word.scan(index).size
     if count_substring_appears > 0
       output[index] = count_substring_appears
     end
  end

  output
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...