代码之家  ›  专栏  ›  技术社区  ›  Vessel

Ruby-包含任意数量元素的所有排列

  •  1
  • Vessel  · 技术社区  · 11 月前

    我想转换数组 [3, 4, 8] [3, 4, 8, 34, 38, 48, 43, 83, 84, 348, 384, 834, 843, 438, 483]

    我试过了 array.permutation 但这只会回来 [348, 384, 834, 843, 438, 483] 。是否有一种干净的方法来做到这一点,而不首先生成所有可能的子集?

    2 回复  |  直到 11 月前
        1
  •  1
  •   Alexander    11 月前

    Array#permutation 接受一个可选参数,告诉它要创建的最大置换大小。

    在你的情况下,你只需要大小的所有排列 0 那么 1 那么 2 , ... 取决于你 input.count .

    所以,这就像创建一个这些数字的范围,映射它们来调用一样简单 permutation 每次使用不同的数字并组合结果:

    def all_permutations_of(input)
      (1..input.count).flat_map do |permutation_length|
        input.permutation(permutation_length).to_a
      end
    end
    
    p all_permutations_of([3, 4, 8])
    # => [
    #   [3], [4], [8],
    #   [3, 4], [3, 8], [4, 3], [4, 8], [8, 3], [8, 4],
    #   [3, 4, 8], [3, 8, 4], [4, 3, 8], [4, 8, 3], [8, 3, 4], [8, 4, 3],
    # ]
    

    如果你想让这些数字成为你在例子中显示的实际数字,你需要一个小函数将它们组合在一起,比如我亲切地称之为“smosh”的这个:

    # Produces a single number from an array of digits
    # E.g. `[1, 2, 3]` becomes `123`
    def smoosh(digits)
      exponent = digits.count
      
      digits.sum do |digit|
        exponent -= 1
        digit * (10 ** exponent)
      end
    end
    
    p all_permutations_of([3, 4, 8]).map { smoosh(_1) }
    # => [3, 4, 8, 34, 38, 43, 48, 83, 84, 348, 384, 438, 483, 834, 843]
    
        2
  •  1
  •   Alex    11 月前

    你可以将每种大小的排列组合在一起,然后将其转换为数组:

    ary = [3, 4, 8]
    Enumerator::Chain.new(
      *ary.map.with_index(1) { ary.permutation(_2) }
    ).map(&:join).map(&:to_i)
    
    #=> [3, 4, 8, 34, 38, 43, 48, 83, 84, 348, 384, 438, 483, 834, 843]