Заменить слова из словаря - PullRequest
1 голос
/ 09 февраля 2010

У меня есть массив хэшей, каждый хэш имеет два ключа: «от» и «до»

@dictionary = [{:to=>"lazy", :from=>"quick"}, {:to=>"flies", :from=>"jumps"}, {:from => "over the", :to => "under the"}]

У меня есть длинная строка

@text = "quick brown fox jumps over the lazy dog"

Как я могу заменить все вхождения от "предложений" до "предложений словаря?"

Вывод должен быть:

ленивая коричневая лиса летит под ленивую собаку

Какой самый эффективный способ?

Ответы [ 4 ]

3 голосов
/ 09 февраля 2010
@dictionary.each do |pair|
  @text.gsub!(/#{pair[:from]}/, pair[:to])
end

Или, если вы предпочитаете одну строку:

@dictionary.each { |pair| @text.gsub!(/#{pair[:from]}/, pair[:to]) }

Это точно такой же код, просто используется { } вместо do end для блока (что обычно является обычной практикой Ruby).

1 голос
/ 09 февраля 2010

Если бы это были только слова без {"over the"=>"under the"}, то я думаю, что нечто подобное будет быстрее, чем сканирование строки снова и снова, как это делают большинство решений здесь.

Сначала я конвертирую массив в чистый хэш

h=Hash.new
@dictionary.each {|ft| h[ft[:from]]=ft[:to]}
=> {"quick"=>"lazy", "over the"=>"under the", "jumps"=>"flies"}

затем я сканирую строковое слово за словом

@text.split(/ /).each{|w| h[w] || w}.join(" ")
=> "lazy brown fox flies over the lazy dog"

Также он не страдает от проблемы множественной замены.

h["brown"]="quick"
=> {"brown"=>"quick", "quick"=>"lazy", "over the"=>"under the", "jumps"=>"flies"}
@text.split(/ /).each{|w| h[w] || w}.join(" ")
=> "lazy quick fox flies over the lazy dog"

Я провел несколько тестов и мне пришлось добавить намного больше пар замены, чем я думал, прежде чем решение, приведенное выше, стало быстрее, чем gsub!.

require 'benchmark'

@dictionary = [{:to=>"lazy", :from=>"quick"}, {:to=>"flies", :from=>"jumps"}, {:from => "over the", :to => "under the"}]
@text = "quick brown fox jumps over the lazy dog" * 10000
Benchmark.bm do |benchmark|
  benchmark.report do
    h=Hash.new
    @dictionary.each {|ft| h[ft[:from]]=ft[:to]}
    result=@text.split(/ /).each{|w| h[w] || w}.join(' ')
  end
  benchmark.report do
    @dictionary.each { |pair| @text.gsub!(/#{pair[:from]}/, pair[:to]) }
  end

  @dictionary+=[{:to=>"black", :from=>"brown"}, {:to=>"ox", :from=>"fox"}, {:to=>"hazy", :from=>"lazy"}, {:to=>"frog", :from=>"dog"}]
  @dictionary=@dictionary*15

  benchmark.report do
    h=Hash.new
    @dictionary.each {|ft| h[ft[:from]]=ft[:to]}
    result=@text.split(/ /).each{|w| h[w] || w}.join(' ')
  end
  benchmark.report do
    @dictionary.each { |pair| @text.gsub!(/#{pair[:from]}/, pair[:to]) }
  end
end

Результаты:

      user     system      total        real
  0.890000   0.060000   0.950000 (  0.962106)
  0.200000   0.020000   0.220000 (  0.217235)
  0.980000   0.060000   1.040000 (  1.042783)
  0.980000   0.030000   1.010000 (  1.011380)

Решение gsub! было в 4,5 раза быстрее всего с тремя замененными парами. При 105 заменяющих парах решение split, наконец, является таким же быстрым, на самом деле оно только на 10% медленнее с 105 заменяющими парами, чем для трех. gsub! стал в пять раз медленнее.

0 голосов
/ 09 февраля 2010
@enhaced_dictionary = @dictionary.inject({}) {|res, e| res[e[:from]] = e[:to]  }
@compiled = @text.split(/\s/).map do |e|
  @enhaced_dictionary[e] ?  @enhaced_dictionary[e] : e
end.join(' ')
0 голосов
/ 09 февраля 2010
@dictionary.inject(@text) {|text, d|
  text.gsub d[:from], d[:to]
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...