Tất cả trừ phần tử cuối cùng của mảng Ruby


139

Giả sử tôi có một mảng Ruby

a = [1, 2, 3, 4]

Nếu tôi muốn tất cả trừ mục đầu tiên, tôi có thể viết a.drop(1), thật tuyệt. Tuy nhiên, nếu tôi muốn tất cả trừ mục cuối cùng , tôi chỉ có thể nghĩ theo cách này

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

nhưng không ai trong số này có vẻ sạch như sử dụng drop. Bất kỳ cách tích hợp nào khác tôi đang thiếu?


Theo globalnerdy.com/2008/07/10/ trên , drop là ruby ​​1.9, thay vì ruby ​​1.8.6
Andrew Grimm

Thế còn màn trình diễn .. Nếu tôi sử dụng những câu trả lời này trong các lần lặp trong 1000 lần .. thì câu nào sẽ thắng?
Ninad

Nói cách khác, giải pháp nào không đi qua mảng dưới mui xe?
Ninad

một cách khác, a - ([a.size])
John

Câu trả lời:


128

Có lẽ...

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

hoặc là

a.take 3

hoặc là

a.first 3

hoặc là

a.pop

cái sẽ trả về cái cuối cùng và để lại mảng với mọi thứ trước nó

hoặc làm cho máy tính hoạt động cho bữa tối của nó:

a.reverse.drop(1).reverse

hoặc là

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
Thêm một phương pháp để Arraycó vẻ như là cách tiếp cận tốt nhất với tôi. Hầu hết các dự án kết thúc với một core_ext.rbtệp có ít phần mở rộng như thế này. Một số thư viện thực tế là tất cả các phần mở rộng như thế này: ActiveSupportví dụ.
rfunduk

Điều đó thật thú vị, tôi đã tự hỏi nó phổ biến như thế nào. Mọi người nghĩ gì về chế độ thơ?
DigitalRoss

5
Làm thế nào để ai đó gửi clipphương pháp này cho cộng đồng Ruby? Tôi thực sự nghĩ rằng cái này nên ở trong đó, và vá khỉ là cái sai .
Dropogans

7
Tôi thích a.reverse.drop(1).reversechiến lược. ;-)
Alex

92

Vì tò mò, tại sao bạn không thích a[0...-1]? Bạn muốn có được một lát của mảng, vì vậy toán tử lát có vẻ như là sự lựa chọn thành ngữ.

Nhưng nếu bạn cần gọi nó ở mọi nơi, bạn luôn có tùy chọn thêm một phương thức có tên thân thiện hơn với lớp Array, như DigitalRoss đề xuất. Có lẽ như thế này:

class Array
    def drop_last
        self[0...-1]
    end
end

Nó chỉ có vẻ như rất nhiều lộn xộn, khi thả rất sạch sẽ. nó không phải là một vấn đề lớn, nhưng khó có thể xác nhận trong nháy mắt rằng nó hoàn toàn chính xác. Nhân tiện, tôi thích tên của bạn drop_lasthơn ...
Peter

Tôi thích sử dụng -1 thanh lịch hơn nhiều so với sử dụng .length
Will Nathan

Tò mò, ý nghĩa của thứ ba đó là .gì?
Joshua Pinter

5
... có nghĩa là không bao gồm mục cuối cùng, -1 là mục cuối cùng. Nếu bạn đã thực hiện hai dấu chấm, thì nó sẽ bao gồm mục cuối cùng, ba dấu chấm thì nó sẽ không bao gồm mục cuối cùng.
ckim

Hãy cẩn thận khi sử dụng toán tử lát để lấy phần đuôi của mảng: nó có thể trả về nil: [][1..-1]-> nil, [][0...-1]->[]
Michael

57

Một mẹo hay nữa

>> *a, b = [1,2,3]
=> [1, 2, 3]
>> a
=> [1, 2]
>> b
=> 3

Thật tuyệt, không biết Ruby đã có thứ này; vì vậy a, *b = [1,2,3]chúng ta sẽ nhìn vào mảng theo kiểu xe hơi / cdr cổ điển.
Nulknob Littlun 23/11/14

Thành thật mà nói, tôi thậm chí không nhớ đã viết bình luận đó: D đã xóa nó ngay bây giờ ...
Petr bela

Soooo đơn giản và tốt đẹp. THX
microspino

43

Nếu bạn muốn thực hiện một pop()thao tác trên một mảng (điều này sẽ dẫn đến mục cuối cùng bị xóa), nhưng bạn quan tâm đến việc lấy mảng thay vì một phần tử xuất hiện, bạn có thể sử dụng tap(&:pop):

> arr = [1, 2, 3, 4, 5]
> arr.pop
=> 5
> arr
=> [1, 2, 3, 4]
> arr.tap(&:pop)
=> [1, 2, 3]

Câu trả lời này là câu trả lời có ý nghĩa nhất đối với người dùng này. Các hoạt động nhân bản đang ở trong tầm tay và nó sử dụng các từ dễ diễn giải && súc tích.
Jerome

2
Đó là một số Ruby trơn tru.
khoảng trống

38

Tôi làm như thế này:

my_array[0..-2]

2
Điều này làm việc tuyệt vời. Tôi bối rối tại sao có một số câu trả lời phức tạp hơn nhiều. Đây có phải là một bổ sung Ruby mới?
Joshua Pinter

@JoshuaPinter nó ở đó từ đầu . Tôi đồng ý rằng đó là cách tiếp cận tốt nhất.
Julien

23

Làm thế nào về việc tăng phương thức thả chính nó, ví dụ như thế này?

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

Sau đó, bạn có thể sử dụng kích thước âm để loại bỏ các phần tử từ cuối, như vậy:

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

19

a[0...-1]có vẻ như là cách tốt nhất Cú pháp cắt mảng được tạo ra cho chính xác mục đích này ...

Ngoài ra, nếu bạn không phiền sửa đổi mảng tại chỗ, bạn có thể gọi a.pop:

>> a = [1, 2, 3, 4]
>> a.pop
>> a
=> [1, 2, 3]

bạn cũng có thể gán phần tử cuối cùng cho một biến để sử dụng sau:b = a.pop
Viktor Fonic

12

Để loại bỏ phần tử cuối cùng trong một dòng với phần còn lại quay lại

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

Nghiêm túc mà nói,

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

11

Đây là cách:

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

Nhưng hãy giải thích cách thức hoạt động của nó:

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

Ví dụ tiếp theo sẽ trả về tất cả các bản ghi, từ vị trí 0 đến cuối cùng

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

Ví dụ tiếp theo sẽ trả hồ sơ từ 1 vị trí đến cuối cùng

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

Và ở đây bạn có những gì bạn cần. Ví dụ tiếp theo sẽ trả về các bản ghi từ vị trí 0 cho đến 1

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

1
Bạn có thể viết -2thay vì -1-1.
bfontaine

Bạn có thể làm a[0...-1](chú ý dấu chấm thứ 3) và nhận được kết quả tương tự a[0..-1-1], bởi vì dấu chấm thứ ba bảo nó loại trừ phần tử kết thúc. Xem điều này để biết thêm chi tiết.
Julien

7

Bạn đã thử "lấy"

a.take(3) 

6
nói chung, đây là a.take(a.size - 1); vâng, tôi đã cân nhắc lựa chọn này
Peter

2

Trả lời : a.τwτ , nhưng bạn phải cài đặt Pyper trước ...

Giới thiệu Pyper: Bạn có biết Lispy carcdrtrả về "đầu tiên" và "phần còn lại" của mảng không? Chỉ với những nhu cầu như của bạn, tôi đã thực hiện một phần mở rộng của cơ chế Lispy này. Nó được gọi pypervà nó cho phép bạn truy cập cả thứ 2, phần còn lại từ thứ 2, thứ 3, phần còn lại từ 3d và cuối cùng, mọi thứ trừ cuối cùng, v.v. Điều đó sẽ không có gì nhiều để viết, nhưng nó cũng cho phép sáng tác chữ cái, giống như caar, cadr, cdadar, vv được biết đến từ 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)

và cuối cùng, câu trả lời cho câu hỏi của bạn:

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

Có nhiều:

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

Sáng tác:

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

Ngoài ra còn có nhiều ký tự lệnh hơn là a..f, u..z0..9đáng chú ý nhất mlà bản đồ:

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

Nhưng các nhân vật lệnh khác quá nóng và không dễ sử dụng vào lúc này.


1
Tôi đang đọc nó vào ngày 1 tháng 4 vì vậy tôi cho rằng đó là một trò đùa ... không. Không có ý tưởng công cụ này tồn tại cho Ruby. :)
Joshua Pinter

1

Điều này tạo ra một mảng mới với tất cả trừ các yếu tố cuối cùng của bản gốc:

ary2 = ary.dup
ary2.pop

Lưu ý rằng một vài người khác đã đề xuất sử dụng #pop. Nếu bạn đồng ý sửa đổi mảng tại chỗ, điều đó tốt. Nếu bạn không ổn với điều đó, thì hãy nhân đôi mảng trước, như trong ví dụ này.


1
Một vài người khác đã đề xuất sử dụng #pop, nếu bạn đồng ý sửa đổi mảng tại chỗ. Nếu bạn không ổn với điều đó, thì hãy nhân đôi mảng trước, như trong ví dụ này.
alegscogs

Đây là một nhận xét quan trọng. Bạn có thể chỉ cần thêm nó vào câu trả lời của bạn là tốt. Vì #pop không có tiếng nổ (!), Thực tế là nó sửa đổi mảng ban đầu có thể thoát khỏi mọi người.
mjnissim

Đây là cách không hiệu quả nếu mảng lớn.
juliangonzalez

1

Tôi thường thấy mình muốn tất cả trừ n phần tử cuối cùng của một mảng. Tôi đã sử dụng chức năng của riêng mình để thực hiện điều này theo cách mà tôi thấy dễ đọc hơn các giải pháp khác:

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

Bây giờ bạn có thể làm như sau:

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

Tôi đã cố tình cho phép ArgumentError để người gọi chịu trách nhiệm về cách họ sử dụng phương thức này. Tôi rất thích nghe ý kiến ​​/ phê bình về phương pháp này.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.