Ruby-测试数组


265

什么是正确的方法:

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

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

还是要获取其中的物品计数?


7
您想要一个实际的数组,还是只是一个类似数组的东西?
凯西·范·斯通·史东

1
Ruby中没有类型安全性。不必担心变量是否为数组。该方法应假定它是,并继续对其进行调用:my_array.count
user132447 2012年

请阅读zgchurch和DigitalRoss的答案,以获取更多惯用的Ruby。
DanT 2015年

Answers:


516

您可能要使用kind_of()

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

31
还有is_a?instance_of?。参见stackoverflow.com/questions/3893278/…–
内森·朗

2
类型检查用于Java。继续,仅对变量调用count。编写单元测试以确保该方法能够按预期工作。
user132447 2012年

14
@ user132447其实Java是类型安全的,所以你不必担心任何检查类型
圣诞怪杰

8
我现在对此表示反对,因为我认为这不是像Ruby这样的语言的好习惯。@zgchurch的答案显然是解决该问题的惯用语。在这种情况下,我认为尝试弄清楚OP的含义而不是盲目地给他a弹枪更有意义……
Per Lundberg 2014年

1
您为什么要使用kind_of?()其他解决方案?关于您的答案相对于他人的益处的一些解释将对将来的读者有所帮助。
AlbertEngelB 2015年

148

你肯定需要是一个数组?您可能可以使用,respond_to?(method)因此您的代码将可用于不一定是数组的类似事物(也许还有其他可数的事物)。如果确实需要array,则描述该Array#kind\_of?方法的帖子最好。

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

1
在这种情况下,我确定它将是一个数组。但是也很高兴知道这种方法。+1
BuddyJoe

有趣的主意,我在数据结构上使用推/弹出。除了数组之外,其他任何东西都会响应那些方法吗?
德鲁

3
如果您想要更类似于数组的内容,则可能需要respond_to?(:to_ary)
安德鲁·格林

21
通常,这是面向对象开发的良好实践。我读了一些人基本上说的话:不要以为您在对象上调用方法。您正在向他们发送消息。如果某个对象知道如何响应您的消息,则无需关心它是什么类,它是否具有名为该方法的方法,或者是否通过method_missing动态创建响应。重要的是,它可以响应您的消息吗?这样可以更好地抽象功能和实现。您可以更改以后使用的对象,只要它仍然可以正确响应即可。
内森·朗

2
唯一的问题是说我想检查某个东西是否是索引可迭代的,因此数组,链接列表等会很酷,但是我不希望像哈希那样的键值存储?
科尔顿·沃吉

58

无需测试Array,即可将任何内容转换为一个级别,Array,因此您的代码只需处理一种情况。

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

Ruby有多种协调API的方法,可以采用一个对象或一个对象数组,因此,猜测为什么要知道某个对象是否为数组,我有一个建议。

图示操作含有大量的魔法你可以看一下,或者你可以拨打Array(something)如果需要的话,这将增加一个阵列封装。这与[*something]这种情况相似。

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

或者,您可以在参数声明中使用splat,然后使用.flatten,从而为您提供了另一种收集器。(为此,您也可以.flatten在上面致电。)

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]"

而且,感谢gregschlom,使用它有时有时会更快,Array(x)因为当它已经存在时,Array它不需要创建新对象。


那么,您是说如果它是单个项目,则使它成为包含单个项目的数组吗?
BuddyJoe

是的,如果已经是一个数组,则无需添加第二个数组包装器就可以保留它。
DigitalRoss

2
别忘了:[*nil] => []。因此,您可能最终会得到一个空数组。
Christopher Oezbek,2014年

3
使用Array(foo)效率比[*foo]
gregschlom '16

23

[1,2,3].is_a? Array 评估为true。


1
这对网站上已有将近七年的答案有什么帮助?
马丁·图尔诺伊

6
@Carpetsmoker没有一个简洁的答案引用is_a?整个线程。最接近的是[1,2,3].is_a? Enumerable。我仍然认为值得一试。
dipole_moment 2016年

4
你知道的..你实际上是对的...我可以发誓我早些时候就在那儿看到过:-/赞成!
马丁·图尔诺伊

16

听起来您正在追求具有某些项目概念的项目。因此,我建议看看是否Enumerable。这也保证了的存在#count

例如,

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

值得注意的是,虽然sizelengthcount数组的所有工作,count是这里的正确含义- (例如,'abc'.length'abc'.size双方的工作,但'abc'.count没有工作,这样的)。

注意:字符串is_a?可枚举,所以也许这不是您想要的...取决于对象数组的概念。



6

还可以考虑使用Array()。从《Ruby社区风格指南》中

在处理要作为数组对待的变量时,请使用Array()而不是显式的Array check或[* var],但不确定是数组。

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

传递哈希时,这将产生意外的结果,因为to_a在添加到新数组的每个参数上都会调用,因此Array({id: 100})返回[[:id, 100]]
brent
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.