Construir un hash de hashes para determinar el valor numérico más grande en Ruby

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

  •  25-09-2019
  •  | 
  •  

Pregunta

Tengo un archivo de datos que se ve así:

FBpp0070000 acyr193594273 acyr 866
FBpp0070000 acyr193577824 acyr 536
FBpp0070000 acyr193693009 acyr 445
FBpp0070000 bomb193605819 bomb 503
FBpp0070000 bomb193676398 bomb 101
FBpp0070001 acyr193618043 acyr 316
FBpp0070001 acyr193617997 acyr 313
FBpp0070001 bomb193638865 bomb 482
FBpp0070001 locu193695159 locu 220
FBpp0070001 locu193638863 locu 220

El archivo de datos tiene ~ 45,000 líneas de largo.

Mi objetivo es tener esto:

FBpp0070000 acyr193594273 acyr 866
FBpp0070000 bomb193605819 bomb 503
FBpp0070001 acyr193618043 acyr 316
FBpp0070001 bomb193638865 bomb 482
FBpp0070001 locu193695159 locu 220

Es decir, mantenga solo esas líneas con la puntuación más alta en la columna 4, para cada valor diferente en la columna 3, para cada valor en la columna 1.

Además, los problemas que estoy viendo son 1) múltiples "claves" duplicadas en la columna 1 y 2) "puntajes" iguales en la columna 4; Solo quiero mantener una instancia de esa "puntuación" duplicada.

En el pasado, he construido un hash en Perl que puede manejar múltiples teclas duplicadas.

Esto es lo que tengo en Ruby hasta ahora.

hash = Hash.new{|h,k| h[k]=Hash.new(&h.default_proc) }  
title = ''

File.open('test1.txt', 'r').each do |line|
  line.chomp!

     query, hit, taxa, score = line.split(/\s/)
     hash[query][hit][taxa] = score

 # end

#p "#{query}: #{taxa}: #{score}"

end
p hash

Entonces, espero que alguien pueda ayudarme a determinar 1) si estoy, de hecho, estoy haciendo esto correctamente, y 2) Si es así, cómo extraer las líneas que necesito.

Gracias.

¿Fue útil?

Solución

Lo siguiente parece hacer lo que desea, dado el ejemplo de entrada que dio anteriormente. Deberá recurrir a los datos al final para obtener el formato de salida que desea.

#!/usr/bin/env ruby

require 'pp'

data = {}
File.open("input.txt", "r").each do |l| 
  l.chomp!
  query, hit, taxa, score = l.split(/\s+/)
  data[query] ||= {}
  data[query][taxa] ||= [0, nil]
  data[query][taxa] = [score.to_i, hit] if score.to_i > data[query][taxa].first
end 

pp data

Esto da:

dj2@Magnus:~/Development/test $ ./out.rb 
{"FBpp0070000"=>
  {"bomb"=>[503, "bomb193605819"], "acyr"=>[866, "acyr193594273"]},
 "FBpp0070001"=>
  {"bomb"=>[482, "bomb193638865"],
   "locu"=>[220, "locu193695159"],
   "acyr"=>[316, "acyr193618043"]}}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top