Tout sauf le dernier élément du tableau Ruby

139

Disons que j'ai un tableau Ruby

a = [1, 2, 3, 4]

Si je veux tout sauf le premier élément, je peux écrire a.drop(1), ce qui est génial. Si je veux tout sauf le dernier article, je ne peux penser qu'à cette façon

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

mais aucun de ceux-ci ne semble aussi propre que l'utilisation drop. Y a-t-il d'autres moyens intégrés qui me manquent?

Peter
la source
Selon globalnerdy.com/2008/07/10/… , la goutte est rubis 1.9, plutôt que ruby ​​1.8.6
Andrew Grimm
Qu'en est-il de la performance ... Si je devais utiliser ces réponses dans des itérations des milliers de fois ... laquelle gagnerait?
Ninad
En d'autres termes, quelle solution ne traverse pas le tableau sous le capot?
Ninad
une autre façon, a - ([a.size])
John

Réponses:

128

Peut-être ...

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

qui renverra le dernier et quittera le tableau avec tout ce qui le précède

ou faire fonctionner l'ordinateur pour son dîner:

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
la source
5
Ajouter une méthode Arrayme semble être la meilleure approche. La plupart des projets se retrouvent avec un core_ext.rbfichier avec de petites extensions comme celle-ci. Certaines bibliothèques sont pratiquement toutes des extensions comme celle-ci: ActiveSupportpar exemple.
rfunduk
C'est intéressant, je me demande à quel point c'est courant. Que pensent les gens du mode poésie?
DigitalRoss
5
Comment quelqu'un soumet-il cette clipméthode à la communauté Ruby? Je pense vraiment que cela devrait être là-dedans, et le patching de singe est la mauvaise chose .
Droogans
7
J'aime la a.reverse.drop(1).reversestratégie. ;-)
Alex
92

Par curiosité, pourquoi n'aimez-vous pas a[0...-1]? Vous voulez obtenir une tranche du tableau, donc l'opérateur de tranche semble être le choix idiomatique.

Mais si vous avez besoin d'appeler cela partout, vous avez toujours la possibilité d'ajouter une méthode avec un nom plus convivial à la classe Array, comme DigitalRoss l'a suggéré. Peut-être comme ceci:

class Array
    def drop_last
        self[0...-1]
    end
end
Mirko Froehlich
la source
il semble juste que beaucoup de désordre, quand la goutte est si propre. ce n'est pas un gros problème, mais il est difficile de confirmer d'un bref coup d'œil que c'est tout à fait exact. Je préfère ton nom, drop_lastau fait ...
Peter
J'adore utiliser -1 tellement plus élégant que d'utiliser .length
Will Nathan
Curieux, quelle est la signification de ce troisième .?
Joshua Pinter
5
... signifie ne pas inclure le dernier élément, Le -1 est le dernier élément. Si vous avez fait deux points, cela inclurait le dernier élément, trois points, puis il n'inclurait pas le dernier élément.
ckim
Faites attention en utilisant l'opérateur slice pour obtenir la queue du tableau: il peut renvoyer nil: [][1..-1]-> nil, [][0...-1]->[]
Michael
57

Un autre truc sympa

>> *a, b = [1,2,3]
=> [1, 2, 3]
>> a
=> [1, 2]
>> b
=> 3
montréal
la source
Bien, je ne savais pas que Ruby avait ça; donc a, *b = [1,2,3]nous permettrait de regarder le tableau d'une manière voiture / cdr classique.
Nobbynob Littlun
Honnêtement, je ne me souviens même pas d'avoir écrit ce commentaire: D l'a supprimé maintenant ...
Petr Bela
Trop simple et sympa. THX
microspino
43

Si vous souhaitez effectuer une pop()opération sur un tableau (ce qui entraînera la suppression du dernier élément), mais que vous souhaitez obtenir le tableau au lieu d'un élément popped, vous pouvez utiliser tap(&:pop):

> arr = [1, 2, 3, 4, 5]
> arr.pop
=> 5
> arr
=> [1, 2, 3, 4]
> arr.tap(&:pop)
=> [1, 2, 3]
kogitoja
la source
Cette réponse est celle qui a le plus de sens sémantiquement pour cet utilisateur. Les opérations du miroir sont à portée de main et il utilise des mots faciles à interpréter et concis.
Jerome
2
C'est un Ruby lisse.
emptywalls
38

Je fais ça comme ça:

my_array[0..-2]
pixelearth
la source
2
Cela fonctionne à merveille. Je ne comprends pas pourquoi il existe un certain nombre de réponses beaucoup plus complexes. Est-ce un nouvel ajout Ruby?
Joshua Pinter
@JoshuaPinter c'est là depuis le début . Je reconnais que c'est de loin la meilleure approche.
Julien
23

Que diriez-vous d'augmenter la méthode drop elle-même, par exemple comme ça?

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

Ensuite, vous pouvez utiliser une taille négative pour supprimer des éléments de la fin, comme ceci:

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

a[0...-1]semble être le meilleur moyen. La syntaxe de découpage de tableau a été créée exactement dans ce but ...

Sinon, si cela ne vous dérange pas de modifier le tableau en place, vous pouvez simplement appeler a.pop:

>> a = [1, 2, 3, 4]
>> a.pop
>> a
=> [1, 2, 3]
dbr
la source
vous pouvez également affecter le dernier élément à une variable pour une utilisation ultérieure:b = a.pop
Viktor Fonic
12

Pour se débarrasser du dernier élément d'une ligne avec le reste retournant

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

Sérieusement,

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

Ceci est le chemin:

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

Mais expliquons comment cela fonctionne:

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

L'exemple suivant retournera tous les enregistrements, de la position 0 au dernier

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

L'exemple suivant renverra les enregistrements d'une position à la dernière

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

Et ici, vous avez ce dont vous avez besoin. L'exemple suivant renverra les enregistrements de la position 0 au dernier-1

a[0..-1-1]
=> [1, 2, 3, 4]
Fran Martinez
la source
1
Vous pouvez écrire à la -2place de -1-1.
bfontaine
Vous pourriez faire a[0...-1](remarquez le 3e point) et obtenir le même résultat que a[0..-1-1], car le troisième point lui dit d'exclure l'élément de fin. Voir ceci pour plus de détails.
Julien
7

Avez-vous essayé de "prendre"

a.take(3) 
Mike Buckbee
la source
6
en général, c'est a.take(a.size - 1); oui, j'ai envisagé cette option.
Peter
2

Réponse:, a.τwτ mais vous devez d'abord installer Pyper ...

Pyper intro: Connaissez-vous Lispy caret le cdrretour du "premier" et du "reste" du tableau? Juste pour des besoins comme les vôtres, j'ai fait une extension de ce mécanisme Lispy. Il s'appelle pyper, et il vous permet d'accéder également au 2ème, au repos du 2ème, au 3ème, au repos de 3d, et aussi au dernier, à tout sauf le dernier, etc. caar, cadr, cdadaretc. connu 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)

et enfin, la réponse à votre question:

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

Il y a plus:

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

Compositions:

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

Il y a aussi plus de caractères de commande que juste a..f, u..zet 0..9, plus particulièrement m, signifiant map:

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

Mais d'autres caractères de commande sont trop chauds et pas très faciles à utiliser pour le moment.

Boris Stitnicky
la source
1
Je lis ceci le 1er avril donc j'ai supposé que c'était une blague ... non. Je n'avais aucune idée que ce truc existait pour Ruby. :)
Joshua Pinter
1

Cela crée un nouveau tableau avec tous les éléments de l'original sauf les derniers:

ary2 = ary.dup
ary2.pop

Notez que quelques autres ont suggéré d'utiliser #pop. Si vous êtes d'accord pour modifier le tableau en place, c'est très bien. Si cela ne vous convient pas, doublez d'abord le tableau, comme dans cet exemple.

alegscogs
la source
1
Quelques autres ont suggéré d'utiliser #pop, si vous êtes d'accord pour modifier le tableau en place. Si cela ne vous convient pas, doublez d'abord le tableau, comme dans cet exemple.
alegscogs
C'est un commentaire important. Vous pouvez également l'ajouter à votre réponse. Puisque #pop n'a pas de bang (!), Le fait qu'il modifie le tableau d'origine peut échapper aux gens.
mjnissim
C'est bien inefficace si le tableau est grand.
juliangonzalez
1

Je me retrouve souvent à vouloir tout sauf les n derniers éléments d'un tableau. J'ai conçu ma propre fonction pour le faire d'une manière que je trouve plus lisible que d'autres solutions:

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

Vous pouvez maintenant effectuer les opérations suivantes:

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

J'ai délibérément autorisé ArgumentError afin que l'appelant soit responsable de la façon dont il utilise cette méthode. J'aimerais entendre les commentaires / critiques de cette approche.

Soumya
la source
-1
a = [1,2,3,4]

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