2010-10-18 8 views
10

Diciamo che ho il seguente array:Fornire un proc a un metodo come un blocco

arr = [[5, 1], [2, 7]] 

e voglio trovare l'elemento minimo, confrontando il secondo elemento degli elementi. L'elemento minimo sarà [5, 1] poiché 1 è inferiore a 7. Posso utilizzare il seguente codice:

arr.min {|a,b| a[1] <=> b[1]} 

Per calcolare il massimo che posso fare lo stesso:

arr.max {|a,b| a[1] <=> b[1]} 

Che dà [2, 7].

Io uso sempre lo stesso blocco. Mi piacerebbe avere quel blocco da qualche parte e fornirlo alla funzione min/max. Speravo qualcosa del tipo:

blo = lambda {|a,b| a[1] <=> b[1]} 
arr.min blo 

funzionava, ma non è così. Qualche idea su come posso farlo?

risposta

23

Utilizzare l'operatore & per trasformare un oggetto Proc in un blocco.

arr.min &blo 
+2

L'unico, che legge attentamente la domanda. – Nakilon

+0

Questo è esattamente quello che stavo cercando. Grazie mille per la risposta! –

+0

@Cristobal forse dovresti "accettare" la risposta che ti soddisfa. Indica agli altri utenti che questa domanda ha avuto risposta e la risposta è stata accettata. –

2

come circa questo?

=> [[5, 4], [9, 5], [2, 7]] 
>> arr.sort!{|x,y| x[1]<=>y[1] } 
=> [[5, 4], [9, 5], [2, 7]] 
>> min,max=arr[0],arr[-1] 
=> [[5, 4], [2, 7]] 
13

@ risposta di sepp2k è quello più generale, ma nel tuo caso specifico, vorrei solo usare

arr.min_by(&:last) 
arr.max_by(&:last) 

dal momento che è molto più evidente di tutte quelle parentesi graffe e parentesi quadre e indici di array che fluttuano intorno.

+0

Anche questo funziona;) –

+0

Questo è quello che stavo cercando, quindi puoi fare 'line_items.max_by (&: quantity)' per esempio. Grazie mille – Dorian

1

Una soluzione più generale a problemi come questo è di evitare completamente gli array annidati e utilizzare invece una classe. Puoi quindi definire l'operatore < => per quella classe, dandoti l'accesso a tutte le funzioni nel Mixin comparabile (http://ruby-doc.org/core/classes/Comparable.html) e fornisci il <, < = , ==,> =, e> operatori e il metodo 'tra?'

Questo è solo un esempio, nella vita reale si usa classi che descrivono ciò che immagazzinano:

class Duo 

    include Comparable 

    def initialize(a, b) 
     @a = a 
     @b = b 
    end 

    def <=>(rhs) 
     @b <=> rhs.b 
    end 

end 

Se si dispone di una serie di Duo oggetto è quindi possibile utilizzare il min, max, e funzioni di ordinamento senza dover definire l'operatore di confronto. Quindi ...

@a = Duo.new(1, 10) 
@b = Duo.new(2, 5) 
@c = Duo.new(3, 1) 

[ @a, @b, @c ].sort 

sarebbe restituire la matrice [@c, @b, @a]

E

[@a, @b, @c].max 

sarebbe tornare @a

Questo è molto più il ' Ruby Way 'di strutture dati nidificate con logica che si basa su posizioni negli array. Ci vuole un po 'più di lavoro all'inizio, ma lo troverai molto più a lungo termine nel.

Ruby è un linguaggio di programmazione molto orientato agli oggetti e fornisce strumenti molto potenti da utilizzare. Consiglio vivamente di leggere un libro come "The Ruby Programming Language" o "The Ruby Way" per avere una panoramica adeguata della potenza della lingua.

+0

Il nome 'Duo' non indica che sarebbe stato ordinato dall'ultimo elemento. Che succede se qualcun altro ha creato un 'Duo' che è stato ordinato dal primo elemento per la parte del progetto, portando a due' Duo 'diversi? –

+0

Beh, questo sarà sempre un problema in qualsiasi codice che scrivi, se crei una classe e qualcun altro la modifica, allora hai un problema. Ma non è una ragione per non farlo. Ovviamente questo era solo un esempio. Nella vita reale avresti un nome di classe molto più descrittivo che descriveva in realtà ciò che veniva archiviato, non solo un generico archivio di due elementi. –

+0

Ciao, grazie mille per la tua risposta. Mi piace molto e sono d'accordo con te, a lungo andare a volte è meglio. In questa occasione, tuttavia, per me è stato più rapido passare il blocco. –

3

Se tutto ciò che serve è minimo e massimo, si potrebbe utilizzare Enumerable#minmax metodo e calcolare entrambi contemporaneamente:

min, max = arr.minmax {|a,b| a[1] <=> b[1]} 
#=> [[5, 1], [2, 7]] 
min 
#=> [5, 1] 
max 
#=> [2, 7] 

Edit: L'inferno, ho appena notato c'è anche minmax_by, in modo da poter combinare con Metodo last e:

min, max = arr.minmax_by &:last 
Problemi correlati