2009-06-01 6 views
5

Ho una funzione che estrae i dati di Excel in un array di hash in questo modo:Cerca hash in una matrice per valore

 

sub set_exceldata { 

    my $excel_file_or = '.\Excel\ORDERS.csv'; 
    if (-e $excel_file_or) { 

     open (EXCEL_OR, $excel_file_or) || die("\n can't open $excel_file_or: $!\n");     
     while() { 

      chomp; 
      my ($id, $date, $product, $batchid, $address, $cost) = split ","; 
      my %a = (id  => $id 
        , date => $date 
        , product => $product 
        , batchid => $batchid 
        , address => $address 
        , cost => $cost 
        ); 
      push (@array_data_or, \%a); 
     } 
     close EXCEL_OR; 
    } 
} 

Compilazione l'array di hash è bene. Tuttavia, la parte difficile è la ricerca di un particolare oggetto (hash) nell'array. Non riesco a trovare articoli che potrebbero avere un ID o 21, o un batchid di 15, o un costo> $ 20 ecc.

Come potrei fare per implementare tale funzione di ricerca?

Grazie a tutti,

+0

Si potrebbe semplicemente spingere un hash ref push anonimo (@array, {id => $ id}); –

+0

Anche se non sono direttamente correlati alla tua domanda, dovresti guardare Text :: xSV per analizzare il file .csv. Solo fare una divisione su "," non è affidabile al 100% per l'analisi. C'è anche un modulo Spreadsheet :: ParseExcel in grado di analizzare i binari di Excel. – jiggy

risposta

18

Con la potenza di grep

my @matching_items = grep { 
    $_->{id} == 21 
} @array_data_or; 

Se sai che ci sarà solo un elemento restituito si può semplicemente fare questo:

my ($item) = grep { 
    $_->{id} == 21 
} @array_data_or; 

(testato, e non ho scritto uno di questi in un istante, ma dovrebbe funzionare)

+0

Grazie per l'intuizione David. Per quanto riguarda la tua soluzione questo restituisce una serie di risultati considerando che poiché ci sarà in realtà solo un'occorrenza è necessario restituire un hash e non un array. Questa soluzione sarebbe ancora valida quando si restituisce un hash anziché un array di hash? –

+1

se sei sicuro che restituirà solo un valore puoi usare $ matching_items [0], oppure my $ matching_items = (grep { $ _-> {id} == 21 } @array_data_or) [0 ]; –

+0

@DidYouJustDoThat: Supponendo che ci sia una sola partita non è necessariamente sicuro. Alcuni dei tuoi esempi (ad esempio costo> 20) potrebbero restituire più articoli. –

5

Se sei sicuro che la ricerca restituisce sempre un solo avvenimento, o se siete interessati a solo la prima partita allora si potrebbe utilizzare la subroutine 'prima' trovato in List::Util

use List::Util; 

my %matching_hash = %{ first { $_->{id} == 21 } @array_data_or }; 

ho racchiuso il richiamo del sottoprogramma in il blocco % {} per garantire che l'RHS valuti un hash.

+0

Il% {} attorno alla chiamata a first() dereferisce l'hashref dall'array, creando una copia (superficiale). Questo potrebbe essere un problema a seconda di come l'OP lo usa. Vorrei invece restituire l'hashref: '$ hr = first {$ _-> {id} == 21} @ array_data_or' –

+0

Anch'io preferirei tornare e usare in seguito l'hashref ma secondo il commento di DidYouJustDoThat alla risposta di David Doward, il poster sta cercando un hash e non un riferimento. – aks

+0

Penso che pronunciare "hash" sia solo una terminologia scadente. Vuole un singolo valore invece di una lista. –