将数组转换为某些数组

时间:2012-03-11 14:35:59

标签: ruby arrays algorithm ruby-1.9.3

我想将Ruby数组(可能包含一些子数组)扩展到另一个数组数组中,就像在这些示例中一样:

示例1:[:foo, :bar]

[
  [:foo, :bar]
]

示例2:[:foo, :bar, [:ki, :ku]]

[
  [:foo, :bar, :ki],
  [:foo, :bar, :ku]
]

示例3:[:foo, :bar, :baz, [:a, :i, :u, :e, :o], :qux]

[
  [:foo, :bar, :baz, :a, :qux],
  [:foo, :bar, :baz, :i, :qux],
  [:foo, :bar, :baz, :u, :qux],
  [:foo, :bar, :baz, :e, :qux],
  [:foo, :bar, :baz, :o, :qux]
]

示例4:[:foo, :bar, :baz, [:a, :i, :u, :e, :o], [1, 2], :qux]

[
  [:foo, :bar, :baz, :a, 1, :qux],
  [:foo, :bar, :baz, :i, 1, :qux],
  [:foo, :bar, :baz, :u, 1, :qux],
  [:foo, :bar, :baz, :e, 1, :qux],
  [:foo, :bar, :baz, :o, 1, :qux],
  [:foo, :bar, :baz, :a, 2, :qux],
  [:foo, :bar, :baz, :i, 2, :qux],
  [:foo, :bar, :baz, :u, 2, :qux],
  [:foo, :bar, :baz, :e, 2, :qux],
  [:foo, :bar, :baz, :o, 2, :qux]
]

示例5:[:foo, [[], :c], :bar]

[
  [:foo, [], :bar],
  [:foo, :c, :bar]
]

示例6:[:foo, [[:a, :b], :c], :bar]

[
  [:foo, [:a, :b], :bar],
  [:foo, :c, :bar]
]

注意:只应展开子数组。这就是为什么,在例子5& 6,子子阵列未扩展。

非常感谢任何建议或代码。

3 个答案:

答案 0 :(得分:8)

我使用product的想法来实现此功能:

def trans(a)
  b = a.map{|e| [e].flatten(1)}
  b.first.product(*b.slice(1..-1))
end

例如,此代码:

puts trans([:foo, :bar]).inspect
puts trans([:foo, :bar, :baz, [:a, :i, :u, :e, :o], [1, 2], :qux]).inspect
puts trans([:foo, [[], :c], :bar]).inspect
puts trans([:foo, [[:a, :b], :c], :bar]).inspect

给出这个:

[[:foo, :bar]]
[[:foo, :bar, :baz, :a, 1, :qux],
 [:foo, :bar, :baz, :a, 2, :qux],
 [:foo, :bar, :baz, :i, 1, :qux],
 [:foo, :bar, :baz, :i, 2, :qux],
 [:foo, :bar, :baz, :u, 1, :qux],
 [:foo, :bar, :baz, :u, 2, :qux],
 [:foo, :bar, :baz, :e, 1, :qux],
 [:foo, :bar, :baz, :e, 2, :qux],
 [:foo, :bar, :baz, :o, 1, :qux],
 [:foo, :bar, :baz, :o, 2, :qux]]
[[:foo, [], :bar],
 [:foo, :c, :bar]]
[[:foo, [:a, :b], :bar],
 [:foo, :c, :bar]]

编辑:上述代码的说明。

一般的想法是我们想要数组中所有元素的产品。如果您查看Array#product的文档,您会发现它符合您的要求 - 我们只需要适当地调用它。

首先,product对数组进行操作,因此我们必须确保原始数组中的所有项都是数组。这是函数第一行的任务:

b = a.map{|e| [e].flatten(1)}

我们正在使用map转换数组中的所有元素。转换生成一个内部带有元素e的数组,然后展平这个新数组。原始元素是一个数组,或者它不是;如果它不是一个数组,[e].flatten(1)将什么也不做,将返回[e];如果它是一个数组,[e]将评估为[[x]],然后将其展平为[x]1告诉flatten只有1级深度。

然后我们要做的就是在第一个元素上调用product作为参数传递修改后的数组的其余元素:

b.first.product(*b.slice(1..-1))

在这里,b.slice(1..-1)表示:从第2个一直到最后一个从b获取元素。最后,星号表示我们不想将数组作为参数传递,而是传递数组的元素。

答案 1 :(得分:2)

似乎你希望有一个有问题的阵列元素的笛卡尔积。 此代码应该适合您:

array = [:foo, :bar, :baz, [:a, :i, :u, :e, :o], [1, 2], :qux]
array.inject([[]]) do |product,element|
  result = []
  if element.is_a?(Array)
    product.each do |tuple|
      element.each do |last|
        result << tuple + [last]
      end
    end
  else
    product.each do |tuple|
      result << tuple + [element]
    end
  end
  result
end

您可以通过将条件移动到循环来简化它,但这会降低效率。

答案 2 :(得分:1)

考虑到您使用的是示例而不是明确的内容,我建议您通过 Array method's documentation 进行拖网。首先,请看下面的方法:

.combination.to_a
.shift
.transpose
.flatten
.zip
.take

你如何实现取决于你是否知道在每种情况下你正在改变什么,或者你是否正在尝试构建通用的东西(即扩展Array类。对于每一个我都将输入数组操作到目标数组中。示例1很简单:

input = [:foo,:bar]
target = Array.new
target << input        => [[:foo,:bar]]

对于其他示例,有多种方法可以实现,具体取决于您尝试执行的操作,以及您希望ruby在使用输入时如何知道该怎么做。在示例2中,第一个是直接写:

input = [:foo, :bar, [:ki, :ku]]
target = Array.new

target << [input[0], input[1], input[2][0]]
target << [input[0], input[1], input[2][1]]

或使用数组方法:

target = input.pop
target = [input, input].zip(target).flatten
target = [target[0..(target.size/2)-1], target[target.size/2..-1]]

或者如果您不知道包含子数组的数组部分,您可以检测到它:

input.each do |i|
  if i.class == Array
    holding = i
  end
end

这实际上取决于你想要如何识别和操纵数组!