Ruby中数组的正值和负值的所有组合

时间:2014-12-07 07:11:10

标签: ruby arrays

我想知道如何在Ruby中使用基于输入数组中的值的所有正值和负值组合来获取数组。顺序无关紧要,但必须适应所有尺寸的输入数组。它必须是灵活的,因此负数可以在输入中,即使我没有在下面的例子中包含它们。

例如:

输入:

a = [1,2,3,4]

输出:

b = [[1,2,3,4],[1,2,3,-4],[1,2,-3,-4],[-1,2,-3,-4]...[1,-2,3,-4],[1,-2,-3,-4],[-1,-2,-3,-4],[-1,-2,-3,4],[-1,-2,3,4],[-1,2,3,4]]

非常感谢您的帮助!

6 个答案:

答案 0 :(得分:3)

当您迭代正面和负面时,您会注意到,应用否定性的模式与您在二进制计数时用于递增位的模式相同。这是因为数组中的每个索引都可以具有两个值中的一个(正数或负数),就像二进制数中的每个位可以具有两个值(0或1)中的一个一样。因此,简单的解决方案是将0和1映射为正和负。然后我们可以只进行正常的Ruby迭代,并检查元素的相应索引位。

a = [1,2,3,4]  # => [1, 2, 3, 4]

signed = [a, a.map(&:-@)]                            # => [[1, 2, 3, 4], [-1, -2, -3, -4]]
(0...2**a.size).each do |n|                          # => 0...16
  p Array.new(a.size) { |i| signed[n[i]][i] }  # => [1, 2, 3, 4], [-1, 2, 3, 4], [1, -2, 3, 4], [-1, -2, 3, 4], [1, 2, -3, 4], [-1, 2, -3, 4], [1, -2, -3, 4], [-1, -2, -3, 4], [1, 2, 3, -4], [-1, 2, 3, -4], [1, -2, 3, -4], [-1, -2, 3, -4], [1, 2, -3, -4], [-1, 2, -3, -4], [1, -2, -3, -4], [-1, -2, -3, -4]
end                                                  # => 0...16

# >> [1, 2, 3, 4]
# >> [-1, 2, 3, 4]
# >> [1, -2, 3, 4]
# >> [-1, -2, 3, 4]
# >> [1, 2, -3, 4]
# >> [-1, 2, -3, 4]
# >> [1, -2, -3, 4]
# >> [-1, -2, -3, 4]
# >> [1, 2, 3, -4]
# >> [-1, 2, 3, -4]
# >> [1, -2, 3, -4]
# >> [-1, -2, 3, -4]
# >> [1, 2, -3, -4]
# >> [-1, 2, -3, -4]
# >> [1, -2, -3, -4]
# >> [-1, -2, -3, -4]

答案 1 :(得分:2)

另一种方式(@ JoshuaCheek答案的变体):

a = [1,2,3,4]

n = a.size
(2**n).times.map { |i|
  ("%0#{n}b" % i).split('').zip(a).map { |b,e| (b=='1') ? e : -e } }
  #=> [[-1, -2, -3, -4], [-1, -2, -3, 4], [-1, -2, 3, -4], [-1, -2, 3, 4],
  #    [-1,  2, -3, -4], [-1,  2, -3, 4], [-1,  2, 3, -4], [-1,  2, 3, 4],
  #    [ 1, -2, -3, -4], [ 1, -2, -3, 4], [ 1, -2, 3, -4], [ 1, -2, 3, 4],
  #    [ 1,  2, -3, -4], [ 1,  2, -3, 4], [ 1,  2, 3, -4], [ 1,  2, 3, 4]]

答案 2 :(得分:2)

虽然其他答案已经涉及Array方法,但Array#repeated_permutation才是真正需要的:

[ 1, -1 ].repeated_permutation( 4 ).map { |p| [ 1, 2, 3, 4 ].zip( p ).map { |u, v| u * v } }

答案 3 :(得分:0)

嗯,Ruby方便地在combination对象上包含Array方法,但首先需要为原始数组中的数字创建相反的值:

a = [1,2,3,4]
b = a.map(&:-@)

然后,您希望将两个数组连接成一个数组:

c = a + b

最后,您可以调用包含所有正值和负值的数组的combination方法:

c.combination(4).to_a # => [[1,2,3,4], [1,2,3,-1], ...]

以下是combination method的文档。

更新:我喜欢Boris Stitnicky提出的建议。以下是对此的修改:

a = [1,2,3,4]

def sign_permutations(arr)
  [1, -1].repeated_permutation(arr.length).map do |signs|
    signs.map.with_index do |sign, index|
      arr[index] * sign
    end
  end
end

puts sign_permutations(a).inspect

答案 4 :(得分:0)

array=[]
[1,-1].each do |a|
    [2,-2].each do |b|
        [3,-3].each do |c|
             [4,-4].each do |d|
                  array<<[a,b,c,d]
              end
          end
     end
end

一旦我把手放在键盘上,我就会详细说明一个更完整的问题

<强>更新: 很多好的答案,这里是递归方式:

@input = [1,2,3,4] # or whatever
@output = []
def pos_neg(ind,in_array)
    a=@input[ind]
    [a,-a].each do |b|
        arr=in_array.dup
        arr[ind]=b
        if @input.size > ind+1
            pos_neg(ind+1,arr)
        else
            @output << arr
        end
    end
end

然后,你运行:

pos_neg(0,[])
@output
[[1, 2, 3, 4],
[1, 2, 3, -4],
[1, 2, -3, 4],
[1, 2, -3, -4],
[1, -2, 3, 4],
[1, -2, 3, -4],
[1, -2, -3, 4],
[1, -2, -3, -4],
[-1, 2, 3, 4],
[-1, 2, 3, -4],
[-1, 2, -3, 4],
[-1, 2, -3, -4],
[-1, -2, 3, 4],
[-1, -2, 3, -4],
[-1, -2, -3, 4],
[-1, -2, -3, -4]]

答案 5 :(得分:0)

以下方法有效 - 基本上,我们在二进制0000到1111(或十进制0到15)之间使用位掩码来决定哪些数字应该是负数(0是正数,1是负数) - 更多细节在评论中以下代码:

require 'pp'
result = []
# consider binary number mask from binary 0000 to 1111, 
# where each digit if 0 uses the positive number, and if 1 uses the negative number
(0..15).each do |mask|
  combin = [] # each combination
  # Next, loop through the four place values (1,2,4,8)
  (0..3).each do |pwr|
    pv = 2 ** pwr # each place value
    if ((mask & pv) == pv) # if the mask has the bit set at this place value, 
      combin << -(pwr + 1) # use the negative of the number (pwr + 1 gives 1, 2, 3, 4 nicely)
    else # if mask doesn't have the bit set at this place value
      combin << (pwr + 1) # use the positive value of the number
    end
  end  
  result << combin 
end
pp result

# Output:  
# [[1, 2, 3, 4],
#  [-1, 2, 3, 4],
#  [1, -2, 3, 4],
#  [-1, -2, 3, 4],
#  [1, 2, -3, 4],
#  [-1, 2, -3, 4],
#  [1, -2, -3, 4],
#  [-1, -2, -3, 4],
#  [1, 2, 3, -4],
#  [-1, 2, 3, -4],
#  [1, -2, 3, -4],
#  [-1, -2, 3, -4],
#  [1, 2, -3, -4],
#  [-1, 2, -3, -4],
#  [1, -2, -3, -4],
#  [-1, -2, -3, -4]]