Alle bis auf das letzte Element des Ruby-Arrays

139

Angenommen, ich habe ein Ruby-Array

a = [1, 2, 3, 4]

Wenn ich alle bis auf den ersten Artikel haben möchte, kann ich schreiben a.drop(1), was großartig ist. Wenn ich aber alle bis auf den letzten Punkt haben möchte , kann ich nur so denken

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

aber keines davon scheint so sauber wie das Verwenden drop. Gibt es noch andere Möglichkeiten, die mir fehlen?

Peter
quelle
Laut globalnerdy.com/2008/07/10/… ist Drop Ruby 1.9 und nicht Ruby 1.8.6
Andrew Grimm
Was ist mit der Leistung? Wenn ich diese Antworten tausende Male in Iterationen verwenden würde ... welche würde gewinnen?
Ninad
Mit anderen Worten, welche Lösung durchläuft kein Array unter der Haube?
Ninad
ein anderer Weg, ein - ([a.size])
John

Antworten:

128

Vielleicht...

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

oder

a.take 3

oder

a.first 3

oder

a.pop

Dadurch wird das letzte zurückgegeben und das Array mit allem davor belassen

oder lassen Sie den Computer für das Abendessen arbeiten:

a.reverse.drop(1).reverse

oder

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
quelle
5
Das Hinzufügen einer Methode Arrayscheint mir der beste Ansatz zu sein. Die meisten Projekte haben eine core_ext.rbDatei mit kleinen Erweiterungen wie dieser. Einige Bibliotheken sind praktisch alle Erweiterungen wie diese: ActiveSupportzum Beispiel.
Rfunduk
Das ist interessant, ich habe mich gefragt, wie häufig es ist. Was denken die Leute über den Poesiemodus?
DigitalRoss
5
Wie reicht jemand diese clipMethode bei der Ruby-Community ein? Ich denke wirklich, dass dies dort drin sein sollte, und Affen-Patching ist das Falsche .
Droogans
7
Ich mag die a.reverse.drop(1).reverseStrategie. ;-)
Alex
92

Warum magst du aus Neugier nicht a[0...-1]? Sie möchten ein Slice des Arrays erhalten, daher scheint der Slice-Operator die idiomatische Wahl zu sein.

Wenn Sie dies jedoch überall aufrufen müssen, haben Sie immer die Möglichkeit, der Array-Klasse eine Methode mit einem benutzerfreundlicheren Namen hinzuzufügen, wie von DigitalRoss vorgeschlagen. Vielleicht so:

class Array
    def drop_last
        self[0...-1]
    end
end
Mirko Froehlich
quelle
Es scheint nur viel Unordnung zu sein, wenn der Tropfen so sauber ist. Es ist keine große Sache, aber auf einen kurzen Blick schwer zu bestätigen, dass es genau richtig ist. Ich bevorzuge drop_lastübrigens Ihren Namen ...
Peter
Ich liebe es, -1 so viel eleganter zu verwenden als .length
Will Nathan
Neugierig, was bedeutet dieses dritte .?
Joshua Pinter
5
... bedeutet, dass das letzte Element nicht enthalten ist. Das -1 ist das letzte Element. Wenn Sie zwei Punkte gemacht haben, würde es das letzte Element enthalten, drei Punkte, dann wird es nicht das letzte Element enthalten.
ckim
Seien Sie vorsichtig, wenn Sie den Slice-Operator verwenden, um das Ende des Arrays zu erhalten: Er kann nil[][1..-1]nil[][0...-1][]
Michael
57

Ein weiterer cooler Trick

>> *a, b = [1,2,3]
=> [1, 2, 3]
>> a
=> [1, 2]
>> b
=> 3
montrealmike
quelle
Schön, wusste nicht, dass Ruby das hatte; so a, *b = [1,2,3]würden sie uns in einer klassischen Auto / cdr Art und Weise auf dem Array zu suchen.
Nobbynob Littlun
Ehrlich gesagt erinnere ich mich nicht einmal daran, diesen Kommentar geschrieben zu haben: D hat ihn jetzt gelöscht ...
Petr Bela
Soooo einfach und nett. THX
Microspino
43

Wenn Sie eine pop()Operation für ein Array ausführen möchten (was dazu führt, dass das letzte Element gelöscht wird), aber das Array anstelle eines geplatzten Elements erhalten möchten, können Sie Folgendes verwenden tap(&:pop):

> arr = [1, 2, 3, 4, 5]
> arr.pop
=> 5
> arr
=> [1, 2, 3, 4]
> arr.tap(&:pop)
=> [1, 2, 3]
kogitoja
quelle
Diese Antwort ist für diesen Benutzer semantisch am sinnvollsten. Die Spiegeloperationen sind zur Hand und es werden Wörter verwendet, die leicht zu interpretieren und kurz sind.
Jerome
2
Das ist ein schlauer Ruby.
leere Wände
37

So mach ich es:

my_array[0..-2]
Pixelerd
quelle
2
Das funktioniert fantastisch. Ich bin verwirrt, warum es eine Reihe weitaus komplexerer Antworten gibt. Ist das eine neue Ruby-Ergänzung?
Joshua Pinter
@JoshuaPinter es ist von Anfang an da . Ich stimme zu, dass dies bei weitem der beste Ansatz ist.
Julien
23

Wie wäre es beispielsweise mit einer Erweiterung der Drop-Methode selbst?

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

Dann können Sie eine negative Größe verwenden, um Elemente vom Ende zu entfernen, wie folgt:

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

a[0...-1]scheint der beste Weg zu sein. Die Array-Slicing-Syntax wurde genau zu diesem Zweck erstellt ...

Wenn es Ihnen nichts ausmacht, das vorhandene Array zu ändern, können Sie alternativ einfach Folgendes aufrufen a.pop:

>> a = [1, 2, 3, 4]
>> a.pop
>> a
=> [1, 2, 3]
dbr
quelle
Sie können einer Variablen auch das letzte Element zur späteren Verwendung zuweisen:b = a.pop
Viktor Fonic
12

Das letzte Element in einer Zeile entfernen, während der Rest zurückkehrt

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

Aber im Ernst,

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

Das ist der Weg:

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

Aber lassen Sie uns erklären, wie das funktioniert:

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

Im nächsten Beispiel werden alle Datensätze von der 0-Position bis zur letzten zurückgegeben

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

Im nächsten Beispiel werden Datensätze von 1 Position bis zur letzten zurückgegeben

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

Und hier haben Sie was Sie brauchen. Im nächsten Beispiel werden Datensätze von der Position 0 bis zur letzten 1 zurückgegeben

a[0..-1-1]
=> [1, 2, 3, 4]
Fran Martinez
quelle
1
Sie können schreiben , -2statt -1-1.
Bfontaine
Sie können dies tun a[0...-1](beachten Sie den 3. Punkt) und das gleiche Ergebnis erzielen wie a[0..-1-1], da der dritte Punkt das Endelement ausschließen soll. Sehen Sie dies für weitere Details.
Julien
7

Haben Sie versucht, "nehmen"

a.take(3) 
Mike Buckbee
quelle
6
im Allgemeinen ist dies a.take(a.size - 1); Ja, ich habe diese Option in Betracht gezogen.
Peter
2

Antwort: a.τwτ aber Sie müssen zuerst Pyper installieren ...

Pyper-Intro: Kennen Sie Lispy carund geben Sie cdr"first" und "rest" des Arrays zurück? Nur für Ihre Bedürfnisse habe ich diesen Lispy-Mechanismus erweitert. Es heißt pyper, und es ermöglicht Ihnen den Zugriff auf die 2., die Pause von der 2., 3., die Pause von 3D und auch die letzte, alles außer der letzten usw. Das wäre nicht viel zu schreiben, aber es erlaubt auch die Komposition von Buchstaben, genau wie caar, cadr, cdadaretc. von Lisp bekannt:

# 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)

und schließlich die Antwort auf Ihre Frage:

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

Es gibt mehr:

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

Kompositionen:

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

Darüber hinaus gibt es mehr als nur Befehl Zeichen a..f, u..zund 0..9, vor allem m, was bedeutet , Karte:

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

Aber andere Befehlszeichen sind zu heiß und im Moment nicht sehr einfach zu bedienen.

Boris Stitnicky
quelle
1
Ich lese das am 1. April, also nahm ich an, dass es ein Witz war ... nein. Hatte keine Ahnung, dass dieses Zeug für Ruby existiert. :)
Joshua Pinter
1

Dadurch wird ein neues Array mit allen bis auf die letzten Elemente des Originals erstellt:

ary2 = ary.dup
ary2.pop

Beachten Sie, dass einige andere vorgeschlagen haben, #pop zu verwenden. Wenn Sie in Ordnung sind, das Array an Ort und Stelle zu ändern, ist das in Ordnung. Wenn Sie damit nicht einverstanden sind, dupen Sie zuerst das Array, wie in diesem Beispiel.

Alecscogs
quelle
1
Einige andere haben die Verwendung von #pop vorgeschlagen, wenn Sie das vorhandene Array ändern möchten. Wenn Sie damit nicht einverstanden sind, dupen Sie zuerst das Array, wie in diesem Beispiel.
Alecscogs
Dies ist ein wichtiger Kommentar. Sie können es auch einfach zu Ihrer Antwort hinzufügen. Da #pop keinen Knall (!) Hat, kann die Tatsache, dass es das ursprüngliche Array ändert, Menschen entgehen.
mjnissim
Dies ist viel ineffizient, wenn das Array groß ist.
Juliangonzalez
1

Ich möchte oft alle bis auf die letzten n Elemente eines Arrays. Ich habe meine eigene Funktion so eingerichtet, dass ich sie besser lesbar finde als andere Lösungen:

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

Jetzt können Sie Folgendes tun:

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

Ich habe den ArgumentError absichtlich zugelassen, damit der Aufrufer dafür verantwortlich ist, wie er diese Methode verwendet. Ich würde gerne Kommentare / Kritik zu diesem Ansatz hören.

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

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