Comment renvoyer une intersection de tableau Ruby avec des éléments en double? (problème de bigrammes dans le coefficient de dés)
-
05-07-2019 - |
Question
J'essaie d'écrire le coefficient de Dice, mais j'ai un problème avec l'intersection de tableaux.
def bigram(string)
string.downcase!
bgarray=[]
bgstring="%"+string+"#"
bgslength = bgstring.length
0.upto(bgslength-2) do |i|
bgarray << bgstring[i,2]
end
return bgarray
end
def approx_string_match(teststring, refstring)
test_bigram = bigram(teststring) #.uniq
ref_bigram = bigram(refstring) #.uniq
bigram_overlay = test_bigram & ref_bigram
result = (2*bigram_overlay.length.to_f)/(test_bigram.length.to_f+ref_bigram.length.to_f)*100
return result
end
Le problème est que, comme & amp; supprime les doublons, je reçois des choses comme celle-ci:
string1="Almirante Almeida Almada"
string2="Almirante Almeida Almada"
puts approx_string_match(string1, string2) => 76.0%
Il devrait renvoyer 100.
La méthode uniq la cloue, mais il y a une perte d'information qui peut amener des correspondances indésirables dans le jeu de données particulier sur lequel je travaille.
Comment puis-je obtenir une intersection avec tous les doublons inclus?
La solution
Comme Yuval F
a déclaré que vous devriez utiliser multiset
. Cependant, il n'y a pas de multiset
dans la bibliothèque standard Ruby, consultez ici et ici .
Si les performances ne sont pas critiques pour votre application, vous pouvez toujours le faire en utilisant Array
avec un code un peu bit.
def intersect a , b
a.inject([]) do |intersect, s|
index = b.index(s)
unless index.nil?
intersect << s
b.delete_at(index)
end
intersect
end
end
a= ["al","al","lc" ,"lc","ld"]
b = ["al","al" ,"lc" ,"ef"]
puts intersect(a ,b).inspect #["al", "al", "lc"]
Autres conseils
De ce lien Je pense que vous ne devriez pas utiliser les ensembles de Ruby mais plutôt multisets, de sorte que chaque bigramme compte le nombre de fois où il apparaît. Peut-être pouvez-vous utiliser cette gem pour les multisets. Cela devrait donner un comportement correct pour les bigrammes récurrents.
Je me suis amusé avec cela pendant un certain temps, en me basant sur la réponse de @pierr, pour finir avec cela.
a = ["al","al","lc","lc","lc","lc","ld"]
b = ["al","al","al","al","al","lc","ef"]
result=[]
h1,h2=Hash.new(0),Hash.new(0)
a.each{|x| h1[x]+=1}
b.each{|x| h2[x]+=1}
h1.each_pair{|key,val| result<<[key]*[val,h2[key]].min if h2[key]!=0}
result.flatten
= > ["al", "al", "lc"]
Cela pourrait être une sorte d'intersection multiset de a
& amp; b
mais ne vous fiez pas à ma parole car je ne l'ai pas suffisamment testée pour en être sûr.