简体   繁体   English

将数组转换为某些数组

[英]Translate an array into some arrays

I would like to expand a Ruby array (which may contain some sub-arrays) into another array of arrays just like in these examples: 我想将Ruby数组(可能包含一些子数组)扩展到另一个数组数组中,就像在这些示例中一样:

Example 1: [:foo, :bar] 例1: [:foo, :bar]

[
  [:foo, :bar]
]

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

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

Example 3: [:foo, :bar, :baz, [:a, :i, :u, :e, :o], :qux] 例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]
]

Example 4: [:foo, :bar, :baz, [:a, :i, :u, :e, :o], [1, 2], :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]
]

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

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

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

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

Note: Only sub-arrays should be expanded. 注意:只应扩展子数组。 That's why, in example 5 & 6, sub-sub-arrays are not expanded. 这就是为什么在示例5和6中,不扩展子子阵列的原因。

Many thanks for any suggestions or piece of code. 非常感谢任何建议或代码。

I used the product idea to reach this function: 我用product想法来实现这个功能:

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

For example, this code: 例如,这段代码:

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

Gives this: 给出这个:

[[: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]]

EDIT: An explanation for the code above. 编辑:上述代码的解释。

The general idea is that we want a product of all elements in the array. 一般的想法是我们想要数组中所有元素的产品。 If you look at the documentation of Array#product , you'll see that it does what you want -- we just have to call it appropriately. 如果你看一下Array#产品的文档,你会发现它做了你想要的 - 我们只需要适当地调用它。

First, product operates on arrays, so we have to make sure that all items in our original array are array themselves. 首先, product在数组上运行,因此我们必须确保原始数组中的所有项都是数组。 This is the task of the first line of the function: 这是函数第一行的任务:

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

We are converting all elements in the array by using map . 我们使用map转换数组中的所有元素。 The conversion makes an array with the element e inside, and then flattens this new array. 转换生成一个内部元素为e的数组,然后展平这个新数组。 Either the original element was an array or it wasn't; 原始元素是数组还是不是; if it wasn't an array, [e].flatten(1) will do nothing and will return [e] ; 如果它不是一个数组, [e].flatten(1)将什么也不做,将返回[e] ; if it was an array, [e] will evaluate to [[x]] , which will then be flattened to [x] . 如果它是一个数组, [e]将评估为[[x]] ,然后将其展平为[x] The 1 tells flatten to go only 1 level deep. 1告诉flatten只有1级深度。

Then all we have to do is call product on the first element passing as arguments the remaining elements of the modified array: 然后我们要做的就是在第一个元素上调用product作为参数传递修改后的数组的其余元素:

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

Here, b.slice(1..-1) means: take elements from b, beginning from the 2nd all the way to the last. 这里, b.slice(1..-1)表示:从第二个开始到最后一个从b获取元素。 Finally, the asterisk indicates that we don't want to pass the array as an argument, but instead the elements of the array. 最后,星号表示我们不想将数组作为参数传递,而是传递数组的元素。

It seems you wish to have a Cartesian product of elements of the array in question. 看来你希望得到有问题的阵列元素的笛卡尔积。 This code should work for you: 此代码应该适合您:

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

You can simplify it a little bit by moving the conditional to the loop, but this will make it less efficient. 您可以通过将条件移动到循环来简化它,但这会降低效率。

Considering you're using examples rather than something explicit I'd suggest having a trawl through the Array method's documentation . 考虑到你使用的是示例而不是显式的东西,我建议通过Array方法的文档进行拖网。 For starters have a look at the following methods: 首先来看看以下方法:

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

How you'd implement depends on whether you know what you're transforming in each case or are you trying to build something generic (ie extend the Array class. For each I'd manipulate the input array into a target array. Example 1 is easy: 你如何实现取决于你是否知道你在每种情况下你正在改变什么,或者你是否正在尝试构建通用的东西(即扩展Array类。对于每一个我都将输入数组操作到目标数组。例1是简单:

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

For the rest of the examples there is multiple ways of getting there depending on what you're trying to do, and how you want ruby to know what to do when presented with the input. 对于其余的示例,有多种方法可以实现,具体取决于您尝试做什么,以及您希望ruby在使用输入时知道该怎么做。 In example 2 the first is to directly write: 在例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]]

Or playing with array methods: 或者使用数组方法:

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

Or if you didn't know which the part of the array which contained a sub-array, you could detect it: 或者,如果您不知道包含子数组的数组部分,您可以检测到它:

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

It really depends on each how you want to identify and manipulate the array! 这实际上取决于你想要识别和操纵数组的方式!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM