Ruby:如何遍历一个可能是也可能不是数组的对象?

时间:2010-03-15 21:32:28

标签: ruby arrays loops

我有一个在用户提交的数据上运行的每个方法。

有时它会是一个数组,有时它不会。

提交示例:

<numbers>
    <number>12345</number>
</numbers>

另一个例子:

<numbers>
    <number>12345</number>
    <number>09876</number>
</numbers>

我一直在尝试each do,但当只有一个号码时,我会收到TypeError (Symbol as array index)错误。

10 个答案:

答案 0 :(得分:10)

我最近问了一个与question相似的{{3}}。您可以使用Array轻松地将任何Ruby对象强制转换为数组。

p Array([1,2,3]) #-> [1,2,3]
p Array(123)     #-> [123]

当然,数组会响应each。因此,如果你强迫每个人进入一个数组,你的问题应该得到解决。

答案 1 :(得分:3)

一个简单的解决方法是检查您的对象是否响应:each;如果没有,请将其包装在一个数组中。

irb(main):002:0> def foo x
irb(main):003:1>    if x.respond_to? :each then x else [x] end
irb(main):005:1> end
=> nil
irb(main):007:0> (foo [1,2,3]).each { |x| puts x }
1
2
3
=> [1, 2, 3]
irb(main):008:0> (foo 5).each { |x| puts x }
5
=> [5]

答案 2 :(得分:3)

看起来你要解决的问题不是你遇到的问题。

TypeError (Symbol as array index)

该错误告诉我你有一个数组,但它正在将它当作一个哈希并在它需要一个整数索引时传入一个符号键。

此外,大多数XML解析器都将子节点作为数组提供,即使只有一个也是如此。所以这不应该是必要的。

对于方法的参数,您可以测试对象类型。这允许您传入单个对象或数组,并且仅当它不是一个数组时才转换为数组,因此您可以从该点开始以相同的方式处理它。

def foo(obj)
  obj = [obj] unless obj.is_a?(Array)
  do_something_with(obj)
end

或者更干净但更神秘的东西

def foo(obj)
  obj = [*obj]
  do_something_with(obj)
end

这利用了splat运算符来展开数组(如果是数组)。所以它将它splats(或不改变它),然后你可以将它包装成一个数组,然后你就可以了。

答案 3 :(得分:2)

我最近处于相同的位置,除了我正在使用的对象是散列或哈希数组。如果您使用的是Rails,则可以使用Array.wrap,因为Array(hash)会将哈希值转换为数组。

Array({foo: "bar"}) #=> [[:foo, "bar"]]
Array.wrap({foo: "bar"}) #=> [{:foo=>"bar"}]
Array.wrap(123) #=> [123]
Array.wrap([123]) #=> [123]

答案 4 :(得分:1)

我有时会使用这个便宜的小技巧:

[might_be_an_array].flatten.each { |x| .... }

答案 5 :(得分:1)

使用splat运算符:

[*1]     # => [1]
[*[1,2]] # => [1,2]

答案 6 :(得分:0)

像马克说的那样,你在寻找“respond_to?”另一种选择是使用这样的条件运算符:

foo.respond_to? :each ? foo.each{|x| dostuff(x)} : dostuff(foo);

你想对每个号码做什么?

答案 7 :(得分:0)

你应该尽量避免使用respond_to吗?消息,因为它不是一个非常面向对象的方法。 检查是否有可能在xml生成器代码中找到当只有一个&lt;“number”&gt;时分配整数值的位置。标记并修改它以返回数组。 也许这是一项复杂的任务,但我会尝试这样做以获得更好的OO设计。

答案 8 :(得分:0)

如果您的输入为x,请使用x.to_a将输入转换为数组。

[1,2,3].to_a
  => [1, 2, 3]
1.to_a
  => [1]
"sample string".to_a
  => ["sample string"]

编辑:较新版本的Ruby似乎不再为某些标准对象定义默认.to_a。您始终可以使用“显式强制转换”语法Array(x)来实现相同的效果。

答案 9 :(得分:0)

我不知道很多关于ruby的任何事情,但我认为你可以(明确地)将输入强制转换为数组 - 特别是考虑到如果输入只是一个元素,那么它会自动生成转换为数组。

你尝试过它吗?