Todos, exceto o último elemento da matriz Ruby

139

Digamos que eu tenho uma matriz Ruby

a = [1, 2, 3, 4]

Se eu quiser tudo, menos o primeiro item, posso escrever a.drop(1), o que é ótimo. Se eu quero tudo menos o último item, só consigo pensar dessa maneira

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

mas nenhum deles parece tão limpo quanto o uso drop. Falta alguma outra maneira embutida?

Peter
fonte
De acordo com globalnerdy.com/2008/07/10/... , gota é o Ruby 1.9, em vez de ruby 1.8.6
Andrew Grimm
E o desempenho? Se eu usasse essas respostas em iterações por milhares de vezes .. qual delas venceria?
Ninad
Em outras palavras, qual solução não atravessa a matriz sob o capô?
Ninad 24/08/11
uma outra maneira, a - ([a.size])
John

Respostas:

128

Possivelmente...

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

ou

a.take 3

ou

a.first 3

ou

a.pop

que retornará o último e deixará a matriz com tudo antes

ou faça o computador funcionar para o jantar:

a.reverse.drop(1).reverse

ou

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
fonte
5
Adicionar um método para Arrayparece a melhor abordagem para mim. A maioria dos projetos acaba com um core_ext.rbarquivo com pequenas extensões como esta. Algumas bibliotecas são praticamente todas as extensões como esta: ActiveSupportpor exemplo.
rfunduk 22/10/09
Isso é interessante, eu me perguntei como é comum. O que as pessoas pensam sobre o modo de poesia?
DigitalRoss
5
Como alguém envia esse clipmétodo para a comunidade Ruby? Eu realmente acho que isso deve estar lá, e a correção de macacos é a coisa errada .
Droogans
7
Eu gosto da a.reverse.drop(1).reverseestratégia. ;-)
Alex
92

Por curiosidade, por que você não gosta a[0...-1]? Você deseja obter uma fatia da matriz, para que o operador de fatia pareça a escolha idiomática.

Mas se você precisar chamar isso em todo o lugar, sempre terá a opção de adicionar um método com um nome mais amigável à classe Array, como sugeriu o DigitalRoss. Talvez assim:

class Array
    def drop_last
        self[0...-1]
    end
end
Mirko Froehlich
fonte
parece muita confusão, quando a gota é tão limpa. não é grande coisa, mas é difícil confirmar rapidamente que está exatamente correto. Eu prefiro o seu nome, drop_lasta propósito ... #
Peter
Gosto muito de usar -1 muito mais elegante do que usando .length
Will Nathan
Curioso, qual é o significado desse terço .?
Joshua Pinter
5
... significa não incluir o último item, -1 é o último item. Se você fez dois pontos, ele incluiria o último item, três pontos e não incluirá o último item.
Ckim 03/04
Tenha cuidado ao usar o operador de fatia para obter o final da matriz: ele pode retornar nil: [][1..-1]-> nil, [][0...-1]->[]
Michael #:
57

Outro truque legal

>> *a, b = [1,2,3]
=> [1, 2, 3]
>> a
=> [1, 2]
>> b
=> 3
montrealmike
fonte
Legal, não sabia que Ruby tinha isso; assim a, *b = [1,2,3], veríamos a matriz de uma maneira clássica de carro / cdr.
Nobbynob Littlun
Sinceramente, eu nem me lembro de escrever esse comentário: D o excluí agora ...
Petr Bela
Tããão simples e agradável. THX
microspino
43

Se você deseja executar uma pop()operação em uma matriz (o que resultará no último item excluído), mas está interessado em obter a matriz em vez de um elemento pop-up, você pode usar tap(&:pop):

> arr = [1, 2, 3, 4, 5]
> arr.pop
=> 5
> arr
=> [1, 2, 3, 4]
> arr.tap(&:pop)
=> [1, 2, 3]
kogitoja
fonte
Essa resposta é a que semanticamente faz mais sentido para esse usuário. As operações de espelhamento estão disponíveis e usam palavras fáceis de interpretar e concisas.
Jerome
2
Isso é Ruby.
emptywalls
38

Eu faço assim:

my_array[0..-2]
pixelearth
fonte
2
Isso funciona de maneira fantástica. Estou confuso por que existem várias respostas muito mais complexas. Esta é uma nova adição ao Ruby?
Joshua Pinter
@ JoshuaPinter está lá desde o início . Concordo que é de longe a melhor abordagem.
Julien
23

Que tal aumentar o próprio método drop, por exemplo, como este?

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

Em seguida, você pode usar um tamanho negativo para remover elementos do final, da seguinte maneira:

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

a[0...-1]parece ser o melhor caminho. A sintaxe de divisão da matriz foi criada exatamente para esse fim ...

Como alternativa, se você não se importa em modificar a matriz, basta chamar a.pop:

>> a = [1, 2, 3, 4]
>> a.pop
>> a
=> [1, 2, 3]
dbr
fonte
você também pode atribuir último elemento de uma variável para uso posterior:b = a.pop
Viktor Fonic
12

Para se livrar do último elemento em uma linha com o restante retornando

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

Sério, porém,

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

Este é o caminho:

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

Mas vamos explicar como isso funciona:

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

O próximo exemplo retornará todos os registros, da posição 0 à última

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

O próximo exemplo retornará registros da 1 posição para a última

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

E aqui você tem o que precisa. O próximo exemplo retornará registros da posição 0 para a última-1

a[0..-1-1]
=> [1, 2, 3, 4]
Fran Martinez
fonte
1
Você pode escrever em -2vez de -1-1.
Bfontaine #
Você pode fazer a[0...-1](observe o terceiro ponto) e obter o mesmo resultado que a[0..-1-1], porque o terceiro ponto diz para excluir o elemento final. Veja isso para mais detalhes.
Julien
7

Você já tentou "levar"

a.take(3) 
Mike Buckbee
fonte
6
em geral, é isso a.take(a.size - 1); sim, considerei essa opção.
Peter
2

Resposta :,a.τwτ mas você precisa instalar o Pyper primeiro ...

Introdução ao Pyper: você conhece Lispy care cdrretorna "primeiro" e "resto" da matriz? Apenas para necessidades como a sua, fiz uma extensão desse mecanismo Lispy. É chamado pypere permite acessar também o 2º, o restante do 2º, o 3º, o restante do 3d e também o último, tudo, exceto o último etc. Isso não seria muito para se escrever, mas também permite a composição de letras, assim como caar, cadr, cdadaretc conhecido a partir 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, finalmente, a resposta para sua pergunta:

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

Há mais:

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

Composições:

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

Há também mais caracteres de comando do que apenas a..f, u..ze 0..9, mais notavelmente m, significando mapa:

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

Mas outros caracteres de comando são muito quentes e não são muito fáceis de usar no momento.

Boris Stitnicky
fonte
1
Estou lendo isso no dia 1º de abril, então achei que era uma piada ... não. Não fazia ideia que esse material existia para Ruby. :)
Joshua Pinter
1

Isso cria uma nova matriz com todos, exceto os últimos elementos do original:

ary2 = ary.dup
ary2.pop

Observe que alguns outros sugeriram o uso de #pop. Se você está bem, modificando a matriz no local, tudo bem. Se você não concorda com isso, duplique a matriz primeiro, como neste exemplo.

alegscogs
fonte
1
Alguns outros sugeriram o uso de #pop, se você estiver bem, modificando a matriz no local. Se você não concorda com isso, duplique a matriz primeiro, como neste exemplo.
alegscogs
Este é um comentário importante. Você também pode adicioná-lo à sua resposta. Como #pop não possui um estrondo (!), O fato de modificar a matriz original pode escapar das pessoas.
Mjnissim 24/10/2013
Isso é ineficiente se a matriz for grande.
juliangonzalez
1

Costumo encontrar-me querendo todos, exceto os últimos n elementos de uma matriz. Eu montei minha própria função para fazer isso de uma maneira que eu acho mais legível que outras soluções:

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

Agora você pode fazer o seguinte:

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

Eu permiti deliberadamente o ArgumentError para que o responsável pela chamada seja responsável por como eles usam esse método. Eu adoraria ouvir comentários / críticas dessa abordagem.

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

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