Ruby - kiểm tra mảng


265

Cách đúng đắn để:

is_array("something") # => false         (or 1)

is_array(["something", "else"]) # => true  (or > 1)

hoặc để có được số lượng các mục trong đó?


7
Bạn có muốn một mảng thực tế, hoặc chỉ một cái gì đó giống như mảng?
Kathy Van Stone

1
Không có loại an toàn trong Ruby. Đừng lo lắng về việc biến của bạn có phải là một mảng hay không. Phương thức sẽ giả định rằng nó là như vậy, và tiếp tục và gọi số đếm trên đó: my_array.count
user132447

Vui lòng đọc câu trả lời của zgecl và DigitalRoss để biết thêm thành ngữ Ruby.
DanT

Câu trả lời:


516

Bạn có thể muốn sử dụng kind_of().

>> s = "something"
=> "something"
>> s.kind_of?(Array)
=> false
>> s = ["something", "else"]
=> ["something", "else"]
>> s.kind_of?(Array)
=> true

31
Cũng có is_a?instance_of?. Xem stackoverflow.com/questions/3893278/ Mạnh
Nathan Long

2
Kiểm tra kiểu là dành cho Java. Đi trước và chỉ cần gọi đếm trên biến. Viết các bài kiểm tra đơn vị để đảm bảo phương thức hoạt động như mong đợi.
dùng132447

14
@ user132447 thực sự java là loại an toàn, do đó bạn không cần phải lo lắng về việc kiểm tra bất kỳ loại nào
grinch

8
Tôi đã đánh giá thấp điều này ngay bây giờ vì tôi không nghĩ rằng đây là một cách thực hành tốt trong ngôn ngữ như Ruby. Câu trả lời của @zgecl rõ ràng là một cách tiếp cận thành ngữ hơn nhiều cho câu hỏi. Trong những trường hợp như thế này, tôi nghĩ sẽ có ý nghĩa hơn nhiều khi thử và tìm hiểu ý nghĩa của OP, thay vì mù quáng đưa cho anh ta một khẩu súng ngắn ...
Per Lundberg

1
Tại sao bạn muốn sử dụng kind_of?()hơn các giải pháp khác? Một số giải thích về lợi ích của câu trả lời của bạn so với những người khác sẽ hữu ích cho độc giả trong tương lai.
AlbertEngelB

148

Bạn có chắc chắn nó cần phải là một mảng? Bạn có thể có thể sử dụng respond_to?(method)để mã của bạn sẽ hoạt động cho những thứ tương tự không nhất thiết là mảng (có thể là một số thứ đáng ghen tị khác). Nếu bạn thực sự cần một array, thì bài viết mô tả Array#kind\_of?phương pháp là tốt nhất.

['hello'].respond_to?('each')

1
Trong trường hợp này tôi chắc chắn nó sẽ là một mảng. Nhưng thật tuyệt khi biết phương pháp này. +1
BuddyJoe

Ý tưởng thú vị, tôi đang sử dụng đẩy / bật trên cấu trúc dữ liệu. Bất cứ điều gì ngoài mảng sẽ đáp ứng với các phương pháp đó?
vẽ

3
Nếu bạn muốn một cái gì đó giống như mảng hơn, bạn có thể muốn respond_to?(:to_ary).
Andrew Grimm

21
Nói chung, đây là một thực tiễn tốt cho phát triển OO. Tôi đọc về nơi mà ai đó đã nói về cơ bản: đừng tưởng tượng rằng bạn đang gọi các phương thức trên các đối tượng của mình. Bạn đang gửi tin nhắn cho họ. Nếu một đối tượng biết cách trả lời tin nhắn của bạn, bạn không quan tâm nó thuộc lớp nào, hoặc liệu nó có một phương thức được đặt tên hay không, hoặc liệu nó có tự động tạo ra một phản hồi thông qua phương thức_missing hay không. Điều quan trọng là, nó có thể trả lời tin nhắn của bạn không? Điều này cho phép trừu tượng hóa tốt hơn của chức năng và thực hiện. Bạn có thể thay đổi đối tượng bạn sử dụng sau này, miễn là nó vẫn phản hồi chính xác.
Nathan Long

2
Vấn đề duy nhất với điều này là tôi muốn kiểm tra xem có thứ gì được lặp lại được lập chỉ mục hay không, vì vậy mảng, danh sách được liên kết, v.v. sẽ rất tuyệt, nhưng tôi không muốn các cửa hàng giá trị chính như băm?
Colton Voege

58

Thay vì kiểm tra Array,chỉ chuyển đổi bất cứ thứ gì bạn có được thành một cấp Array,để mã của bạn chỉ cần xử lý một trường hợp.

t = [*something]     # or...
t = Array(something) # or...
def f *x
    ...
end

Ruby có nhiều cách khác nhau để hài hòa một API có thể lấy một đối tượng hoặc một mảng các đối tượng, vì vậy, hãy đoán xem tại sao bạn muốn biết nếu một cái gì đó một Array, tôi có một gợi ý.

Các splat điều hành chứa rất nhiều ma thuật bạn có thể nhìn lên, hoặc bạn chỉ có thể gọi Array(something)đó sẽ thêm một wrapper Mảng nếu cần thiết. Nó tương tự như [*something]trong trường hợp này.

def f x
  p Array(x).inspect
  p [*x].inspect
end
f 1         # => "[1]"
f [1]       # => "[1]"
f [1,2]     # => "[1, 2]"

Hoặc, bạn có thể sử dụng splat trong khai báo tham số và sau đó .flatten, cung cấp cho bạn một loại trình thu thập khác. (Đối với vấn đề đó, bạn cũng có thể gọi .flattenở trên.)

def f *x
  p x.flatten.inspect
end         # => nil
f 1         # => "[1]"
f 1,2       # => "[1, 2]"
f [1]       # => "[1]"
f [1,2]     # => "[1, 2]"
f [1,2],3,4 # => "[1, 2, 3, 4]"

Và, cảm ơn gregschlom , đôi khi chỉ cần sử dụng nhanh hơn Array(x)bởi vì khi nó đã Arraykhông cần thiết phải tạo một đối tượng mới.


Vì vậy, bạn đang nói nếu nó là một mục duy nhất nó làm cho nó một mảng với một mục duy nhất trong đó?
BuddyJoe

Có, và nếu nó đã là một mảng, nó sẽ giữ nó mà không cần thêm một trình bao bọc mảng thứ hai.
DigitalRoss

2
Đừng quên : [*nil] => []. Vì vậy, bạn có thể kết thúc với một mảng trống.
Christopher Oezbek

3
Sử dụng Array(foo)hiệu quả hơn nhiều so với[*foo]
gregschlom

23

[1,2,3].is_a? Array đánh giá là đúng.


1
Điều này thêm gì vào câu trả lời đã có trên trang web trong gần bảy năm ..?
Martin Tournoij

6
@Carpetsmoker không có câu trả lời ngắn gọn mà tham chiếu is_a?trong toàn bộ chủ đề này. Gần nhất là a [1,2,3].is_a? Enumerable. Tôi vẫn nghĩ rằng nó có giá trị trong khi có câu trả lời này.
lưỡng cực

4
Bạn biết đấy .. bạn thực sự đúng ... Tôi có thể đã thề rằng tôi đã thấy điều đó sớm hơn: - / Có một upvote!
Martin Tournoij

16

Có vẻ như bạn đang theo đuổi thứ gì đó có khái niệm về vật phẩm. Vì vậy, tôi khuyên bạn nên xem nếu nó là Enumerable. Điều đó cũng đảm bảo sự tồn tại của #count.

Ví dụ,

[1,2,3].is_a? Enumerable
[1,2,3].count

lưu ý rằng, trong khi size, lengthcounttất cả các công việc cho mảng, countlà ý nghĩa đúng ở đây - (ví dụ, 'abc'.length'abc'.sizecả hai đều hoạt động, nhưng 'abc'.countkhông hoạt động như vậy).

Chú ý: một chuỗi is_a? Vô số, vì vậy có lẽ đây không phải là điều bạn muốn ... phụ thuộc vào khái niệm của bạn về một mảng giống như đối tượng.


11

Thử:

def is_array(a)
    a.class == Array
end

EDIT : Câu trả lời khác tốt hơn nhiều so với của tôi.


6

Cũng xem xét sử dụng Array(). Từ Hướng dẫn Phong cách Cộng đồng Ruby :

Sử dụng Mảng () thay vì kiểm tra Mảng rõ ràng hoặc [* var], khi xử lý một biến bạn muốn coi là Mảng, nhưng bạn không chắc chắn đó là một mảng.

# bad
paths = [paths] unless paths.is_a? Array
paths.each { |path| do_something(path) }

# bad (always creates a new Array instance)
[*paths].each { |path| do_something(path) }

# good (and a bit more readable)
Array(paths).each { |path| do_something(path) }

Điều này sẽ tạo ra kết quả bất ngờ khi truyền Hash vì to_ađược gọi trên mỗi đối số được thêm vào mảng mới, vì vậy Array({id: 100})trả về[[:id, 100]]
brent
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.