Semua kecuali elemen terakhir dari array Ruby

139

Katakanlah saya memiliki array Ruby

a = [1, 2, 3, 4]

Jika saya ingin semua kecuali item pertama, saya bisa menulis a.drop(1), yang bagus. Jika saya ingin semua kecuali item terakhir , saya hanya bisa memikirkan cara ini

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

tapi tak satu pun dari ini tampak sebersih menggunakan drop. Adakah cara bawaan lain yang saya lewatkan?

Peter
sumber
Menurut globalnerdy.com/2008/07/10/... , drop adalah ruby ​​1.9, bukan ruby ​​1.8.6
Andrew Grimm
Bagaimana dengan kinerja .. Jika saya menggunakan jawaban ini dalam iterasi sebanyak 1000 kali .. yang mana yang akan menang?
Ninad
Dengan kata lain, solusi mana yang tidak melintasi array di bawah kap?
Ninad
dengan cara lain, a - ([ukuran]])
John

Jawaban:

128

Mungkin...

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

atau

a.take 3

atau

a.first 3

atau

a.pop

yang akan mengembalikan yang terakhir dan meninggalkan array dengan segalanya sebelumnya

atau buat komputer berfungsi untuk makan malamnya:

a.reverse.drop(1).reverse

atau

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
sumber
5
Menambahkan metode Arraysepertinya pendekatan terbaik bagi saya. Sebagian besar proyek berakhir dengan core_ext.rbfile dengan ekstensi kecil seperti ini. Beberapa perpustakaan secara praktis semua ekstensi seperti ini: ActiveSupportmisalnya.
rfunduk
Itu menarik, saya bertanya-tanya seberapa umum itu. Apa yang orang pikirkan tentang mode puisi?
DigitalRoss
5
Bagaimana seseorang mengirim clipmetode ini ke komunitas Ruby? Saya benar-benar berpikir ini seharusnya ada di sana, dan menambal monyet adalah Hal yang Salah .
Droogan
7
Saya suka a.reverse.drop(1).reversestrateginya. ;-)
Alex
92

Karena penasaran, mengapa Anda tidak suka a[0...-1]? Anda ingin mendapatkan sepotong array, sehingga operator slice sepertinya pilihan idiomatik.

Tetapi jika Anda perlu memanggil ini di mana-mana, Anda selalu memiliki opsi untuk menambahkan metode dengan nama yang lebih ramah ke kelas Array, seperti yang disarankan DigitalRoss. Mungkin seperti ini:

class Array
    def drop_last
        self[0...-1]
    end
end
Mirko Froehlich
sumber
sepertinya banyak kekacauan, ketika drop sangat bersih. ini bukan masalah besar, tetapi sulit untuk memastikan bahwa itu benar. Saya lebih suka nama Anda,, drop_lastomong-omong ...
Peter
Saya suka menggunakan -1 jauh lebih elegan daripada menggunakan .length
Will Nathan
Penasaran, apa arti ketiga itu .?
Joshua Pinter
5
... berarti tidak termasuk item terakhir, -1 adalah item terakhir. Jika Anda melakukan dua titik, maka itu akan termasuk item terakhir, tiga titik maka itu tidak akan termasuk item terakhir.
ckim
Hati-hati menggunakan operator slice untuk mendapatkan buntut array: ia dapat kembali nil: [][1..-1]-> nil, [][0...-1]->[]
Michael
57

Trik keren lainnya

>> *a, b = [1,2,3]
=> [1, 2, 3]
>> a
=> [1, 2]
>> b
=> 3
montrealmike
sumber
Bagus, tidak sadar Ruby punya ini; jadi a, *b = [1,2,3]mari kita lihat array dalam mode mobil / cdr klasik.
Nobbynob Littlun
Jujur, saya bahkan tidak ingat menulis komentar itu: D menghapusnya sekarang ...
Petr Bela
Sangat sederhana dan bagus. THX
microspino
43

Jika Anda ingin melakukan pop()operasi pada array (yang akan menghasilkan item terakhir dihapus), tetapi Anda tertarik untuk mendapatkan array daripada elemen yang muncul, Anda dapat menggunakan tap(&:pop):

> arr = [1, 2, 3, 4, 5]
> arr.pop
=> 5
> arr
=> [1, 2, 3, 4]
> arr.tap(&:pop)
=> [1, 2, 3]
kogitoja
sumber
Jawaban ini adalah yang semantik paling masuk akal bagi pengguna ini. Operasi cermin sudah dekat dan menggunakan kata-kata yang mudah diartikan && ringkas.
Jerome
2
Itu adalah beberapa Ruby yang apik.
emptywalls
38

Saya melakukannya seperti ini:

my_array[0..-2]
pixelearth
sumber
2
Ini bekerja dengan fantastis. Saya bingung mengapa ada sejumlah jawaban yang jauh lebih kompleks. Apakah ini tambahan Ruby baru?
Joshua Pinter
@ JoshuaPinter sudah ada sejak awal . Saya setuju bahwa sejauh ini pendekatan terbaik.
Julien
23

Bagaimana kalau menambah metode drop itu sendiri, misalnya seperti ini?

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

Kemudian Anda dapat menggunakan ukuran negatif untuk menghapus elemen dari ujung, seperti:

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

a[0...-1]sepertinya cara terbaik. Sintaks pengiris array diciptakan untuk tujuan ini ...

Atau, jika Anda tidak keberatan memodifikasi array di tempat, Anda bisa memanggil a.pop:

>> a = [1, 2, 3, 4]
>> a.pop
>> a
=> [1, 2, 3]
dbr
sumber
Anda juga dapat menetapkan elemen terakhir ke variabel untuk digunakan nanti:b = a.pop
Viktor Fonic
12

Untuk menghilangkan elemen terakhir dalam satu baris dengan sisanya kembali

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

Serius,

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

Begini caranya:

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

Tapi mari kita jelaskan bagaimana ini bekerja:

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

Contoh berikutnya akan mengembalikan semua catatan, dari 0 posisi ke terakhir

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

Contoh berikutnya akan mengembalikan catatan dari 1 posisi ke posisi terakhir

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

Dan di sini Anda memiliki apa yang Anda butuhkan. Contoh berikutnya akan mengembalikan catatan dari 0 posisi ke 1 terakhir

a[0..-1-1]
=> [1, 2, 3, 4]
Fran Martinez
sumber
1
Anda bisa menulis -2alih-alih -1-1.
bfontaine
Anda dapat melakukan a[0...-1](perhatikan titik ke-3) dan mendapatkan hasil yang sama dengan a[0..-1-1], karena titik ketiga memberitahu untuk mengecualikan elemen akhir. Lihat ini untuk lebih jelasnya.
Julien
7

Sudahkah Anda mencoba "ambil"

a.take(3) 
Mike Buckbee
sumber
6
secara umum, ini a.take(a.size - 1); ya, saya mempertimbangkan opsi ini.
Peter
2

Jawab :,a.τwτ tetapi Anda harus menginstal Pyper terlebih dahulu ...

Pyper intro: Apakah Anda tahu Lispy cardan cdrmengembalikan "pertama" dan "sisanya" dari array? Hanya untuk kebutuhan seperti kebutuhan Anda, saya membuat perpanjangan mekanisme Lispy ini. Ini disebut pyper, dan memungkinkan Anda untuk mengakses juga ke-2, istirahat dari ke-2, ke-3, istirahat dari 3d, dan juga yang terakhir, semuanya kecuali yang terakhir dll. Itu tidak akan banyak untuk ditulis, tetapi juga memungkinkan komposisi huruf, seperti caar, cadr, cdadardll diketahui dari 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)

dan akhirnya, jawaban untuk pertanyaan Anda:

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

Masih ada lagi:

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

Komposisi:

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

Ada juga lebih banyak karakter perintah dari sekadar a..f, u..zdan 0..9, yang paling penting m, yang berarti peta:

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

Tetapi karakter perintah lainnya terlalu panas dan tidak mudah digunakan saat ini.

Boris Stitnicky
sumber
1
Saya membaca ini pada 1 April jadi saya berasumsi itu lelucon ... tidak. Tidak tahu barang ini ada untuk Ruby. :)
Joshua Pinter
1

Ini membuat array baru dengan semua kecuali elemen terakhir dari aslinya:

ary2 = ary.dup
ary2.pop

Perhatikan bahwa beberapa orang lain menyarankan untuk menggunakan #pop. Jika Anda ok memodifikasi array di tempatnya, tidak apa-apa. Jika Anda tidak setuju dengan itu, dup duplikat array terlebih dahulu, seperti dalam contoh ini.

alegscog
sumber
1
Beberapa orang lain menyarankan menggunakan #pop, jika Anda boleh memodifikasi array di tempatnya. Jika Anda tidak setuju dengan itu, dup duplikat array terlebih dahulu, seperti dalam contoh ini.
alegscogs
Ini komentar penting. Anda mungkin menambahkannya ke jawaban Anda juga. Karena #pop tidak memiliki bang (!), Fakta bahwa ia memodifikasi array asli mungkin lolos dari orang.
mjnissim
Ini cara yang tidak efisien jika arraynya besar.
juliangonzalez
1

Saya sering menemukan diri saya menginginkan semua kecuali elemen terakhir dari array. Saya telah memperjelas fungsi saya sendiri untuk melakukan ini dengan cara yang menurut saya lebih mudah dibaca daripada solusi lain:

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

Sekarang Anda dapat melakukan hal berikut:

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

Saya sengaja mengizinkan ArgumentError sehingga penelepon bertanggung jawab atas cara mereka menggunakan metode ini. Saya ingin mendengar komentar / kritik terhadap pendekatan ini.

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

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