2010-02-09 2 views
1

J'ai un tableau de hachages, chaque hachage a deux touches: « de » et « à »Remplacer les mots d'un dictionnaire

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

J'ai une longue chaîne

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

Comment puis-je remplacer toutes les occurrences de phrases «de» par des phrases «du» vers le dictionnaire?

La sortie doit être:

lazy brown fox flies under the lazy dog

Quelle est la façon la plus efficace?

+1

Ne serait-il pas plus logique de stocker le dictionnaire comme un hachage? '@dictionary = {'paresseux' => 'rapide', 'mouches' => 'saute', 'sur' '=>' sous '}' – kejadlen

Répondre

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

Ou si vous préférez sur une seule ligne:

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

Il est exactement le même code, juste en utilisant { } au lieu de do end pour le bloc (qui tend être la pratique générale de Ruby).

+0

"all occurences", donc au lieu de 'sub' devrait être' gsub'. – NVI

+0

Bon point, merci NV. Mis à jour maintenant – mlambie

0
@dictionary.inject(@text) {|text, d| 
    text.gsub d[:from], d[:to] 
} 
+0

@dictionary = [{: to => "fou bob", : de => "paresseux"}, {: à => "fou ben",: de => "fou bob"}] "renard brun rapide saute par-dessus le chien fou ben" Comme vous pouvez le voir, le le même texte est substitué deux fois, est-ce que quelqu'un connaît une solution d'exécution unique (ne remplaçant pas les remplacements précédents)? Bon travail @NV, merci – astropanic

+0

Quelle sortie espérez-vous? "Le renard brun rapide saute par-dessus le chien fou" ou pas? – NVI

+0

Je veux dire dans mon commentaire précédent, la première substitution de bob fainéant à folle est plus tard remplacée par de bob fou à mad ben. Il ne devrait pas remplacer les substitutions existantes. – astropanic

0
@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

'IndexError: la chaîne ne correspond pas' –

1

S'il n'y avait que des mots sans le {"over the"=>"under the"} alors je pense que quelque chose comme ça serait plus rapide que de scanner la chaîne encore et encore comme la plupart des solutions ici.

D'abord je convertir le tableau à un Hash pur

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

je scanne le mot de chaîne par mot

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

En outre, il ne souffre pas du problème de substitution multiple.

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" 

J'ai fait quelques points de repère et je devais ajouter beaucoup plus paires de remplacement que je pensais avant que la solution ci-dessus a plus vite que 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]} 
    [email protected](/ /).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"}] 
    @[email protected]*15 

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

Les résultats:

 
     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) 

La solution gsub! était 4,5 fois plus rapide avec seulement trois paires de remplacement. Avec 105 paires de remplacement, la solution split est finalement aussi rapide, elle n'a en réalité que 10% de moins de temps avec 105 paires de remplacement que pour trois. Le gsub! a été cinq fois plus lent.

+0

Je ne pense pas que 'split 'et' join' est une bonne idée. Que se passe-t-il si '@text =" fox rapide paresseux \ n survole le chien paresseux "'? – NVI

Questions connexes