Como devolver um cruzamento array Ruby com elementos duplicados? (Problema com bigramas em Dice Coeficiente)

StackOverflow https://stackoverflow.com/questions/1600168

Pergunta

Eu estou tentando Coeficiente de roteiro Dice, mas eu estou tendo um pouco de um problema com a intersecção matriz.

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

O problema é, como e remove duplicatas, fico com coisas como esta:

string1="Almirante Almeida Almada"
string2="Almirante Almeida Almada"

puts approx_string_match(string1, string2) => 76.0%

Ele deve retornar 100.

As unhas método uniq-lo, mas há perda de informações, o que pode trazer correspondências indesejadas no conjunto de dados particular que eu estou trabalhando.

Como posso obter uma interseção com todas as duplicações?

Foi útil?

Solução

Como Yuval F disse que você deve usar multiset. No entanto, há nomultiset em Ruby biblioteca padrão, Take a olhar para aqui aqui .

Se o desempenho não é tão crítico para a sua aplicação, você ainda pode fazê-lo usingArray com um código bit pouco.

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"]

Outras dicas

A partir este link Eu acredito que você não deve usar conjuntos de Ruby mas sim multisets, de modo que cada bigram será contado o número de vezes que aparece. Talvez você possa usar este jóia para multisets. Isso deve dar um comportamento correto para bigramas recorrentes.

Eu brinquei com isso, com base na resposta de @pierr, por um tempo e acabamos com isso.

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"]

Esta poderia ser uma espécie de intersecção multiset de a & b mas não tome minha palavra para ela, porque eu não testei o suficiente para ter certeza.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top