Todos menos el último elemento de la matriz Ruby

139

Digamos que tengo una matriz Ruby

a = [1, 2, 3, 4]

Si quiero todo menos el primer elemento, puedo escribir a.drop(1), lo cual es genial. Sin embargo, si quiero todo menos el último elemento, solo puedo pensar de esta manera

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

pero ninguno de estos parece tan limpio como el uso drop. ¿Alguna otra forma incorporada que me falta?

Peter
fuente
De acuerdo con globalnerdy.com/2008/07/10/… , la caída es ruby ​​1.9, en lugar de ruby ​​1.8.6
Andrew Grimm
¿Qué pasa con el rendimiento ... Si tuviera que usar estas respuestas en iteraciones por miles de veces ... cuál ganaría?
Ninad
En otras palabras, ¿qué solución no atraviesa la matriz debajo del capó?
Ninad
de otra manera, a - ([a.size])
John

Respuestas:

128

Quizás...

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

que devolverá el último y dejará la matriz con todo lo anterior

o hacer que la computadora funcione para la 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]
DigitalRoss
fuente
55
Agregar un método Arrayparece ser el mejor enfoque para mí. La mayoría de los proyectos terminan con un core_ext.rbarchivo con pequeñas extensiones como esta. Algunas bibliotecas son prácticamente todas las extensiones como esta: ActiveSupportpor ejemplo.
rfunduk
Eso es interesante, me he preguntado qué tan común es. ¿Qué piensa la gente sobre el modo poesía?
DigitalRoss
55
¿Cómo envía alguien este clipmétodo a la comunidad Ruby? Realmente creo que esto debería estar allí, y el parche de monos es lo incorrecto .
Droogans 01 de
77
Me gusta la a.reverse.drop(1).reverseestrategia ;-)
Alex
92

Por curiosidad, ¿por qué no te gusta? a[0...-1] ? Desea obtener un segmento de la matriz, por lo que el operador de segmento parece la opción idiomática.

Pero si necesita llamar a esto por todas partes, siempre tiene la opción de agregar un método con un nombre más amigable a la clase Array, como sugiere DigitalRoss. Quizás así:

class Array
    def drop_last
        self[0...-1]
    end
end
Mirko Froehlich
fuente
simplemente parece un montón de desorden, cuando la caída es tan limpia. No es un gran problema, pero es difícil de confirmar a simple vista que es exactamente correcto. Prefiero tu nombre, drop_lastpor cierto ...
Peter
Me encanta usar -1 mucho más elegante que usar .length
Will Nathan
Curioso, ¿cuál es el significado de ese tercero .?
Joshua Pinter el
55
... significa no incluir el último elemento. El -1 es el último elemento. Si hiciera dos puntos, entonces incluiría el último elemento, tres puntos, entonces no incluirá el último elemento.
ckim
Tenga cuidado al usar el operador de división para obtener la cola de la matriz: puede devolver nil: [][1..-1]-> nil, [][0...-1]->[]
Michael
57

Otro truco genial

>> *a, b = [1,2,3]
=> [1, 2, 3]
>> a
=> [1, 2]
>> b
=> 3
montrealmike
fuente
Bien, no sabía que Ruby tenía esto; así a, *b = [1,2,3]que nos dejaría mirar la matriz de una manera clásica de auto / cdr.
Nobbynob Littlun
Honestamente, ni siquiera recuerdo haber escrito ese comentario: D lo eliminó ahora ...
Petr Bela
Tan simple y agradable. THX
microspino
43

Si desea realizar una pop()operación en una matriz (que dará como resultado el último elemento eliminado), pero está interesado en obtener la matriz en lugar de un elemento emergente, puede usar tap(&:pop):

> arr = [1, 2, 3, 4, 5]
> arr.pop
=> 5
> arr
=> [1, 2, 3, 4]
> arr.tap(&:pop)
=> [1, 2, 3]
kogitoja
fuente
Esta respuesta es la que semánticamente tiene más sentido para este usuario. Las operaciones espejo están a la mano y utiliza palabras que son fáciles de interpretar && concisas.
Jerome
2
Eso es un poco de rubí.
paredes vacías
38

Lo hago así:

my_array[0..-2]
pixelearth
fuente
2
Esto funciona fantásticamente. Estoy confundido por qué hay una serie de respuestas mucho más complejas. ¿Es esta una nueva adición de Ruby?
Joshua Pinter el
@JoshuaPinter está ahí desde el principio . Estoy de acuerdo en que es, con mucho, el mejor enfoque.
Julien
23

¿Qué tal aumentar el método de caída en sí mismo, por ejemplo así?

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

Luego puede usar un tamaño negativo para eliminar elementos del final, así:

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

a[0...-1]Parece la mejor manera. La sintaxis de corte de matriz se creó exactamente para este propósito ...

Alternativamente, si no le importa modificar la matriz en su lugar, simplemente puede llamar a.pop:

>> a = [1, 2, 3, 4]
>> a.pop
>> a
=> [1, 2, 3]
dbr
fuente
También puede asignar el último elemento a una variable para su uso posterior:b = a.pop
Viktor Fonic
12

Para deshacerse del último elemento en una línea con el resto regresando

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

Hablando en serio,

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

Esta es la forma:

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

Pero expliquemos cómo funciona esto:

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

El siguiente ejemplo devolverá todos los registros, desde la posición 0 hasta el último

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

El siguiente ejemplo devolverá los registros de 1 posición al último

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

Y aquí tienes lo que necesitas. El siguiente ejemplo devolverá los registros de la posición 0 a last-1

a[0..-1-1]
=> [1, 2, 3, 4]
Fran Martinez
fuente
1
Puedes escribir en -2lugar de -1-1.
bfontaine
Podría hacerlo a[0...-1](observe el tercer punto) y obtener el mismo resultado que a[0..-1-1], porque el tercer punto le dice que excluya el elemento final. Vea esto para más detalles.
Julien
7

¿Has intentado "tomar"

a.take(3) 
Mike Buckbee
fuente
66
en general, esto es a.take(a.size - 1); Sí, consideré esta opción.
Peter
2

Respuesta: a.τwτ pero primero debes instalar Pyper ...

Introducción de Pyper: ¿Conoces a Lispy cary cdrdevuelve "primero" y "resto" de la matriz? Solo para las necesidades como la suya, hice una extensión de este mecanismo Lispy. Se llama pypery le permite acceder también a la 2da, descansar de la 2da, 3ra, descansar de la 3d y también la última, todo excepto la última, etc. Eso no sería mucho sobre lo que escribir, pero también permite la composición de letras, al igual que caar, cadr, cdadaretc. conocido de 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)

y finalmente, la respuesta a tu pregunta:

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

Hay más:

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

Composiciones

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

También hay más caracteres de comando que solo a..f, u..zy 0..9, más notablemente m, significa mapa:

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

Pero otros caracteres de comando son demasiado calientes y no muy fáciles de usar en este momento.

Boris Stitnicky
fuente
1
Estoy leyendo esto el 1 de abril, así que supuse que era una broma ... no. No tenía idea de que esto existía para Ruby. :)
Joshua Pinter
1

Esto crea una nueva matriz con todos menos los últimos elementos del original:

ary2 = ary.dup
ary2.pop

Tenga en cuenta que algunos otros han sugerido usar #pop. Si está bien modificando la matriz en su lugar, está bien. Si no está de acuerdo con eso, duplique la matriz primero, como en este ejemplo.

alegscogs
fuente
1
Algunos otros han sugerido usar #pop, si está bien, modifique la matriz en su lugar. Si no está de acuerdo con eso, duplique la matriz primero, como en este ejemplo.
alegscogs
Este es un comentario importante. También puede agregarlo a su respuesta también. Como #pop no tiene una explosión (!), El hecho de que modifique la matriz original podría escapar de las personas.
mjnissim
Esto es muy ineficiente si la matriz es grande.
juliangonzalez
1

A menudo me encuentro con ganas de todos menos los últimos n elementos de una matriz. He preparado mi propia función para hacer esto de una manera que me parece más legible que otras soluciones:

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

Ahora puedes hacer lo siguiente:

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

Deliberadamente he permitido el ArgumentError para que la persona que llama sea responsable de cómo usan este método. Me encantaría escuchar comentarios / críticas de este enfoque.

Soumya
fuente
-1
a = [1,2,3,4]

a[0..(a.length - 2)]
=> [1,2,3]
George Lucas
fuente