Tutti tranne l'ultimo elemento dell'array Ruby


139

Diciamo che ho un array Ruby

a = [1, 2, 3, 4]

Se voglio tutto tranne il primo elemento, posso scrivere a.drop(1), il che è fantastico. Se voglio tutto tranne l' ultimo articolo, però, posso solo pensare a questo modo

a[0..-2]   # or
a[0...-1]

ma nessuno di questi sembra pulito come l'utilizzo drop. Mi mancano altri modi integrati?


Secondo globalnerdy.com/2008/07/10/… , drop è ruby ​​1.9, anziché ruby ​​1.8.6
Andrew Grimm,

Che dire della performance .. Se dovessi usare queste risposte nelle iterazioni per migliaia di volte .. quale vincerebbe?
Ninad,

In altre parole, quale soluzione non attraversa l'array sotto il cofano?
Ninad,

un altro modo, a - ([a.size])
John

Risposte:


128

Forse...

a = t               # => [1, 2, 3, 4]
a.first a.size - 1  # => [1, 2, 3]

o

a.take 3

o

a.first 3

o

a.pop

che restituirà l'ultimo e lascerà l'array con tutto ciò che lo precede

o fai funzionare il computer per la sua cena:

a.reverse.drop(1).reverse

o

class Array
  def clip n=1
    take size - n
  end
end
a          # => [1, 2, 3, 4]
a.clip     # => [1, 2, 3]
a = a + a  # => [1, 2, 3, 4, 1, 2, 3, 4]
a.clip 2   # => [1, 2, 3, 4, 1, 2]

5
L'aggiunta di un metodo Arraysembra l'approccio migliore per me. La maggior parte dei progetti finisce con un core_ext.rbfile con piccole estensioni come questa. Alcune librerie sono praticamente tutte estensioni come questa: ActiveSupportper esempio.
rfunduk,

È interessante, mi chiedevo quanto fosse comune. Cosa pensano le persone della modalità poesia?
DigitalRoss,

5
In che modo qualcuno invia questo clipmetodo alla community di Ruby? Penso davvero che dovrebbe esserci, e il patch-monkey è la cosa sbagliata .
Droogans,

7
Mi piace la a.reverse.drop(1).reversestrategia. ;-)
Alex

92

Per curiosità, perché non ti piace a[0...-1]? Si desidera ottenere una porzione dell'array, quindi l'operatore sezione sembra la scelta idiomatica.

Ma se hai bisogno di chiamarlo ovunque, hai sempre la possibilità di aggiungere un metodo con un nome più amichevole alla classe Array, come suggerito da DigitalRoss. Forse così:

class Array
    def drop_last
        self[0...-1]
    end
end

sembra un sacco di disordine, quando la caduta è così pulita. non è un grosso problema, ma è difficile confermare a colpo d'occhio che è esattamente giusto. Preferisco il tuo nome, drop_lasta proposito ...
Peter,

Adoro usare -1 molto più elegante di usare .length
Will Nathan il

Curioso, qual è il significato di quel terzo .?
Joshua Pinter

5
... significa non includere l'ultimo elemento, -1 è l'ultimo elemento. Se hai fatto due punti, includerebbe l'ultimo elemento, tre punti quindi non includerà l'ultimo elemento.
ckim

Fai attenzione usando l'operatore slice per ottenere la coda dell'array: potrebbe restituire nil: [][1..-1]-> nil, [][0...-1]->[]
Michael

57

Un altro trucco interessante

>> *a, b = [1,2,3]
=> [1, 2, 3]
>> a
=> [1, 2]
>> b
=> 3

Bello, non sapeva che Ruby aveva questo; quindi a, *b = [1,2,3]vorremmo guardare l'array in un modo classico auto / cdr.
Nobbynob Littlun,

Onestamente, non ricordo nemmeno di aver scritto quel commento: D lo ha cancellato ora ...
Petr Bela,

Davvero semplice e carino. THX
microspino

43

Se desideri eseguire pop()un'operazione su un array (che comporterà l'eliminazione dell'ultimo elemento), ma sei interessato a ottenere l'array anziché un elemento spuntato, puoi utilizzare tap(&:pop):

> arr = [1, 2, 3, 4, 5]
> arr.pop
=> 5
> arr
=> [1, 2, 3, 4]
> arr.tap(&:pop)
=> [1, 2, 3]

Questa risposta è quella che semanticamente ha più senso per questo utente. Le operazioni del mirror sono a portata di mano e utilizza parole facili da interpretare e concise.
Girolamo

2
Questo è un bel rubino.
emptywalls

38

Lo faccio così:

my_array[0..-2]

2
Funziona in modo fantastico. Sono confuso perché ci sono un numero di risposte molto più complesse. È una nuova aggiunta di Ruby?
Joshua Pinter

@JoshuaPinter è lì fin dall'inizio . Sono d'accordo che è di gran lunga l'approccio migliore.
Julien,

23

Che ne dici di aumentare il metodo drop stesso, ad esempio in questo modo?

class Array
  def drop(n)
    n < 0 ? self[0...n] : super
  end
end

Quindi puoi utilizzare una dimensione negativa per rimuovere gli elementi dall'estremità, in questo modo:

[1, 2, 3, 4].drop(-1) #=> [1, 2, 3]
[1, 2, 3, 4].drop(-2) #=> [1, 2]

19

a[0...-1]sembra il modo migliore. La sintassi di suddivisione in array è stata creata proprio per questo scopo ...

In alternativa, se non ti dispiace modificare l'array in atto, puoi semplicemente chiamare a.pop:

>> a = [1, 2, 3, 4]
>> a.pop
>> a
=> [1, 2, 3]

puoi anche assegnare l'ultimo elemento a una variabile per un uso successivo:b = a.pop
Viktor Fonic

12

Per sbarazzarsi dell'ultimo elemento in una riga con il resto che ritorna

[1, 2, 4, 5, 6].reverse.drop(1).reverse

Seriamente però,

[1,2,3,4][0..-2]
#=> [1,2,3]

11

Questo è il modo:

[1,2,3,4,5][0..-1-1]

Ma spieghiamo come funziona:

a = [1,2,3,4,5]

Il prossimo esempio restituirà tutti i record, dalla posizione 0 all'ultimo

a[0..-1]
=> [1, 2, 3, 4, 5]

Il prossimo esempio restituirà i record da 1 posizione all'ultima

a[1..-1]
=> [2, 3, 4, 5]

E qui hai quello che ti serve. Il prossimo esempio restituirà i record dalla posizione 0 all'ultimo-1

a[0..-1-1]
=> [1, 2, 3, 4]

1
Puoi scrivere -2invece di -1-1.
bfontaine,

Potresti farlo a[0...-1](nota il terzo punto) e ottenere lo stesso risultato di a[0..-1-1], perché il terzo punto gli dice di escludere l'elemento finale. Vedi questo per maggiori dettagli.
Julien

7

Hai provato a "prendere"

a.take(3) 

6
in generale, questo è a.take(a.size - 1); si, ho considerato questa opzione.
Peter,

2

Risposta:, a.τwτ ma devi prima installare Pyper ...

Introduzione di Pyper: conosci Lispy care cdrrestituisce "primo" e "resto" dell'array? Proprio per le esigenze come la tua, ho fatto un'estensione di questo meccanismo di Lispy. Si chiama pypere ti permette di accedere anche al 2o, resto dal 2o, 3o, resto da 3d, e anche ultimo, tutto tranne lo scorso ecc. Non sarebbe molto da scrivere, ma consente anche la composizione di lettere, proprio come caar, cadr, cdadarecc nota dal Lisp:

# First, gem install pyper
require 'pyper'
include Pyper
a = %w/lorem ipsum dolor sit amet/
# To avoid confusion with other methods, and also because it resembles a rain gutter,
# Greek letter τ is used to delimit Pyper methods:
aaτ #=> "lorem"
adτ #=> ["ipsum", "dolor", "sit", "amet"]
abτ #=> "ipsum"
aeτ #=> ["dolor", "sit", "amet"]
acτ #=> "dolor" (3rd)
azτ #=> "amet" (last)
ayτ #=> "sit" (2nd from the end)
axτ #=> "dolor" (3rd from the end)

e infine, la risposta alla tua domanda:

awτ #=> ["lorem", "ipsum", "dolor", "sit"] (all except last)

C'è dell'altro:

auτ #=> ["lorem", "ipsum", "dolor"] (all except last 2)
a1τ #=> ["lorem", "ipsum"] (first 2)
a8τ #=> (last 2)
a7τ #=> (last 3)

composizione:

awydτ #=> "olor" (all except 1st letter of the last word of all-except-last array)

Ci sono anche più caratteri di comando che solo a..f, u..ze 0..9, più in particolare m, nel senso mappa:

awmbτ #=> ["o", "p", "o", "i"] (second letters of all-except-last array)

Ma altri personaggi di comando sono troppo caldi e non molto facili da usare al momento.


1
Lo sto leggendo il 1 ° aprile, quindi ho pensato che fosse uno scherzo ... no. Non avevo idea che questa roba esistesse per Ruby. :)
Joshua Pinter

1

Questo crea un nuovo array con tutti tranne gli ultimi elementi dell'originale:

ary2 = ary.dup
ary2.pop

Nota che alcuni altri hanno suggerito di usare #pop. Se stai bene modificando l'array sul posto, va bene. Se non ti va bene, duplica prima l'array, come in questo esempio.


1
Alcuni altri hanno suggerito di usare #pop, se stai bene modificando l'array in atto. Se non ti va bene, duplica prima l'array, come in questo esempio.
alegscogs,

Questo è un commento importante Potresti semplicemente aggiungerlo anche alla tua risposta. Poiché #pop non ha il botto (!), Il fatto che modifichi l'array originale potrebbe sfuggire alle persone.
mjnissim,

Questo è inefficiente se l'array è grande.
juliangonzalez,

1

Mi ritrovo spesso a desiderare tutto tranne gli ultimi n elementi di un array. Ho truccato la mia funzione per farlo in un modo che trovo più leggibile rispetto ad altre soluzioni:

class Array
  def all_but_the_last(n)
    self.first(self.size - n)
  end
end

Ora puoi fare quanto segue:

arr = ["One", "Two", "Three", "Four", "Five"]
# => ["One", "Two", "Three", "Four", "Five"]

arr.all_but_the_last(1)
# => ["One", "Two", "Three", "Four"]

arr.all_but_the_last(3)
# => ["One", "Two"]

arr.all_but_the_last(5)
# => []

arr.all_but_the_last(6)
# ArgumentError: negative array size

Ho deliberatamente consentito l'ArgumentError in modo che il chiamante sia responsabile dell'utilizzo di questo metodo. Mi piacerebbe sentire commenti / critiche a questo approccio.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.