Wszystko oprócz ostatniego elementu tablicy Ruby

139

Powiedzmy, że mam tablicę Ruby

a = [1, 2, 3, 4]

Jeśli chcę wszystko oprócz pierwszej, mogę napisać a.drop(1), co jest świetne. Jeśli jednak chcę wszystko oprócz ostatniego , mogę myśleć tylko w ten sposób

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

ale żaden z nich nie wydaje się tak czysty jak używanie drop. Brakuje mi jakichś innych wbudowanych sposobów?

Piotr
źródło
Według globalnerdy.com/2008/07/10/… , drop to ruby ​​1.9, a nie ruby ​​1.8.6
Andrew Grimm
A co z wydajnością… Gdybym używał tych odpowiedzi w iteracjach tysiące razy… która z nich by wygrała?
Ninad
Innymi słowy, które rozwiązanie nie przechodzi przez tablicę pod maską?
Ninad
w inny sposób a - ([a.rozmiar])
John

Odpowiedzi:

128

Być może...

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

lub

a.take 3

lub

a.first 3

lub

a.pop

co zwróci ostatnią i pozostawi tablicę ze wszystkim przed nią

lub spraw, aby komputer działał na obiad:

a.reverse.drop(1).reverse

lub

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
źródło
5
Dodanie metody do Arraywydaje mi się najlepszym podejściem. Większość projektów kończy się na core_ext.rbpliku z małymi rozszerzeniami, takimi jak ten. Niektóre biblioteki są praktycznie wszystkimi takimi rozszerzeniami: ActiveSupportna przykład.
rfunduk
To ciekawe, zastanawiałem się, jak to jest powszechne. Co ludzie myślą o trybie poezji?
DigitalRoss
5
W jaki sposób ktoś może przesłać tę clipmetodę społeczności Ruby? Naprawdę uważam, że to powinno tam być, a łatanie małp jest niewłaściwą rzeczą .
Droogans
7
Podoba mi się a.reverse.drop(1).reversestrategia. ;-)
Alex
92

Z ciekawości, dlaczego nie lubisz a[0...-1]? Chcesz uzyskać wycinek tablicy, więc operator wycinka wydaje się idiomatycznym wyborem.

Ale jeśli chcesz wywoływać to wszędzie, zawsze masz możliwość dodania metody o bardziej przyjaznej nazwie do klasy Array, jak zasugerował DigitalRoss. Może tak:

class Array
    def drop_last
        self[0...-1]
    end
end
Mirko Froehlich
źródło
po prostu wydaje się, że jest dużo bałaganu, gdy kropla jest tak czysta. nie jest to wielka sprawa, ale na pierwszy rzut oka trudno stwierdzić, że jest dokładnie w porządku. Nawiasem mówiąc, wolę twoje imię drop_last...
Peter,
Uwielbiam używać -1 o wiele bardziej eleganckiego niż używanie .length
Will Nathan
Ciekawe, jakie jest znaczenie tego trzeciego .?
Joshua Pinter
5
... oznacza brak ostatniej pozycji, -1 to ostatnia pozycja. Jeśli zrobiłeś dwie kropki, to będzie zawierał ostatni element, trzy kropki, wtedy nie będzie zawierał ostatniego elementu.
ckim
Uważaj, używając operatora plasterka, aby uzyskać koniec tablicy: może zwrócić nil: [][1..-1]-> nil, [][0...-1]->[]
Michael
57

Kolejna fajna sztuczka

>> *a, b = [1,2,3]
=> [1, 2, 3]
>> a
=> [1, 2]
>> b
=> 3
montrealmike
źródło
Fajnie, nie wiedziałem, że Ruby to ma; tak a, *b = [1,2,3]by spójrzmy na tablicy w klasycznym samochód / CDR mody.
Nobbynob Littlun
Szczerze mówiąc, nawet nie pamiętam, jak pisałem ten komentarz: D usunąłem go teraz ...
Petr Bela
Baaardzo proste i przyjemne. THX
microspino
43

Jeśli chcesz wykonać pop()operację na tablicy (co spowoduje usunięcie ostatniego elementu), ale jesteś zainteresowany uzyskaniem tablicy zamiast elementu wyskakującego, możesz użyć tap(&:pop):

> arr = [1, 2, 3, 4, 5]
> arr.pop
=> 5
> arr
=> [1, 2, 3, 4]
> arr.tap(&:pop)
=> [1, 2, 3]
kogitoja
źródło
Ta odpowiedź jest semantycznie najbardziej sensowna dla tego użytkownika. Operacje zwierciadlane są dostępne i używa słów, które są łatwe do interpretacji i zwięzłe.
Jerome
2
To jakiś zgrabny Ruby.
emptywalls
38

Robię to tak:

my_array[0..-2]
pixelearth
źródło
2
Działa to fantastycznie. Nie wiem, dlaczego istnieje wiele znacznie bardziej złożonych odpowiedzi. Czy to nowy dodatek do Rubiego?
Joshua Pinter
@JoshuaPinter jest tam od początku . Zgadzam się, że to zdecydowanie najlepsze podejście.
Julien
23

A co powiesz na rozszerzenie samej metody upuszczania, na przykład w ten sposób?

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

Następnie możesz użyć rozmiaru ujemnego, aby usunąć elementy z końca, na przykład:

[1, 2, 3, 4].drop(-1) #=> [1, 2, 3]
[1, 2, 3, 4].drop(-2) #=> [1, 2]
axelarge
źródło
19

a[0...-1]wydaje się najlepszym sposobem. Składnia wycinania tablic została stworzona właśnie w tym celu ...

Alternatywnie, jeśli nie masz nic przeciwko modyfikowaniu tablicy w miejscu, możesz po prostu wywołać a.pop:

>> a = [1, 2, 3, 4]
>> a.pop
>> a
=> [1, 2, 3]
dbr
źródło
możesz także przypisać ostatni element do zmiennej do późniejszego wykorzystania:b = a.pop
Viktor Fonic
12

Pozbyć się ostatniego elementu w jednej linii, a reszta wraca

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

Ale naprawdę,

[1,2,3,4][0..-2]
#=> [1,2,3]
boulder_ruby
źródło
11

To jest sposób:

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

Ale wyjaśnijmy, jak to działa:

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

Następny przykład zwróci wszystkie rekordy, od pozycji 0 do ostatniej

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

Następny przykład zwróci rekordy od 1 pozycji do ostatniej

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

I tutaj masz to, czego potrzebujesz. Następny przykład zwróci rekordy od pozycji 0 do ostatniej-1

a[0..-1-1]
=> [1, 2, 3, 4]
Fran Martinez
źródło
1
Możesz -2zamiast tego pisać -1-1.
bfontaine
Możesz to zrobić a[0...-1](zwróć uwagę na trzecią kropkę) i uzyskać ten sam wynik, co a[0..-1-1], ponieważ trzecia kropka mówi jej, aby wykluczyć element końcowy. Zobacz to, aby uzyskać więcej informacji.
Julien
7

Czy próbowałeś „wziąć”

a.take(3) 
Mike Buckbee
źródło
6
ogólnie jest to a.take(a.size - 1); tak, rozważałem tę opcję.
Peter
2

Odpowiedź: a.τwτ ale najpierw musisz zainstalować Pypera ...

Pyper intro: Czy znasz Lispy cari zwracasz cdr„pierwszy” i „reszta” tablicy? Tylko dla potrzeb takich jak Twoje, stworzyłem rozszerzenie tego mechanizmu Lispy. Nazywa się pyperi pozwala na dostęp również do 2, reszta od 2, 3, reszta z 3d, a także ostatnia, wszystko oprócz ostatniego itp. Nie byłoby o czym pisać, ale pozwala również na składanie liter, tak jak caar, cadr, cdadaritd. wiadomo od Lispie:

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

i na koniec odpowiedź na Twoje pytanie:

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

Jest więcej:

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

Kompozycje:

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

Istnieje również więcej znaków niż tylko polecenie a..f, u..zi 0..9, przede wszystkim m, czyli mapa:

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

Ale inne postacie poleceń są w tej chwili zbyt gorące i niezbyt łatwe w użyciu.

Boris Stitnicky
źródło
1
Czytam to 1 kwietnia, więc założyłem, że to żart ... nie. Nie miałem pojęcia, że ​​te rzeczy istnieją dla Rubiego. :)
Joshua Pinter
1

To tworzy nową tablicę zawierającą wszystkie elementy oryginału oprócz ostatnich:

ary2 = ary.dup
ary2.pop

Zwróć uwagę, że kilka innych osób zasugerowało użycie #pop. Jeśli możesz modyfikować tablicę w miejscu, w porządku. Jeśli nie jesteś z tym w porządku, najpierw duplikuj tablicę, jak w tym przykładzie.

alegscogs
źródło
1
Kilku innych zasugerowało użycie #pop, jeśli możesz zmodyfikować tablicę w miejscu. Jeśli nie jesteś z tym w porządku, najpierw duplikuj tablicę, jak w tym przykładzie.
alegscogs
To jest ważny komentarz. Możesz po prostu dodać to również do swojej odpowiedzi. Ponieważ #pop nie ma huku (!), Fakt, że modyfikuje oryginalną tablicę, może umknąć ludziom.
mjnissim
Jest to mało wydajne, jeśli tablica jest duża.
juliangonzalez
1

Często okazuje się, że chcę mieć wszystkie elementy tablicy oprócz ostatnich n. Skonfigurowałem własną funkcję, aby robić to w sposób, który uważam za bardziej czytelny niż inne rozwiązania:

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

Teraz możesz wykonać następujące czynności:

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

Celowo dopuściłem ArgumentError, aby wywołujący był odpowiedzialny za sposób, w jaki używają tej metody. Chciałbym usłyszeć komentarze / krytykę tego podejścia.

Soumya
źródło
-1
a = [1,2,3,4]

a[0..(a.length - 2)]
=> [1,2,3]
George Lucas
źródło