Costruire un hash di hash per determinare il più grande valore numerico in Ruby

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

  •  25-09-2019
  •  | 
  •  

Domanda

Ho un file di dati che assomiglia a questo:

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

Il file di dati è lungo ~ 45.000 righe.

Il mio obiettivo è avere questo:

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

Vale a dire, conservare solo quelle linee con il punteggio più alto nella colonna 4, per ogni valore diverso nella colonna 3, per ciascun valore nella colonna 1.

Inoltre, i problemi che sto vedendo sono 1) "tasti" multipli e duplicati nei punteggi uguali della colonna 1 e 2) nella colonna 4; Voglio conservare solo un'istanza di quel duplicato "punteggio".

In passato ho costruito un hash in perl in grado di gestire più chiavi duplicate.

Ecco cosa ho finora in Ruby.

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

Quindi, spero che qualcuno possa aiutarmi a determinare 1) se, in effetti, lo faccio correttamente e 2) in tal caso, come estrarre le linee di cui ho bisogno.

Grazie.

È stato utile?

Soluzione

Quanto segue sembra fare quello che vuoi, dato l'esempio di input che hai dato sopra. Dovrai ricorrere ai dati alla fine per ottenere il formato di output che desideri.

#!/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

Questo da:

dj2@Magnus:~/Development/test $ ./out.rb 
{"FBpp0070000"=>
  {"bomb"=>[503, "bomb193605819"], "acyr"=>[866, "acyr193594273"]},
 "FBpp0070001"=>
  {"bomb"=>[482, "bomb193638865"],
   "locu"=>[220, "locu193695159"],
   "acyr"=>[316, "acyr193618043"]}}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top