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?


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]

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

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

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]

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]

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]

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]

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]

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]

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) 

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.


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.


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.


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.