【问题标题】:Select array permutations where pattern elements match rule选择模式元素匹配规则的数组排列
【发布时间】:2017-07-09 05:45:40
【问题描述】:

给定一个包含五个元素的数组ary

ary = [true, true, true, false, false]

我想采用ary 的所有排列,其中两个false 值是不连续的,考虑到最后一个位置(索引4)环绕到第一个位置(索引0):

[true, false, true, false, true] #=> Selected
[true, true, false, true, false] #=> Selected
[false, true, true, true, false] #=> Rejected

我认为答案可能归结为selecteach_with_index 方法。我不确定如何使用逻辑表达式关联数组中的元素。

【问题讨论】:

    标签: arrays ruby


    【解决方案1】:

    快速而肮脏的方法可能是扩展数组以考虑包装:

    array = [ true, true, true, false, false ]
    
    array.permutation.to_a.uniq.map do |set|
      [ set[-1] ] + set + [ set[0 ] ]
    end.select do |set|
      set.chunk_while { |b,a| b == a }.all? do |chunk|
        chunk[0] == true or chunk.length == 1
      end
    end.map do |set|
      set[1, set.length - 2]
    end
    

    这会产生:

    # => [
    #   [true, true, false, true, false],
    #   [true, false, true, true, false],
    #   [true, false, true, false, true],
    #   [false, true, true, false, true],
    #   [false, true, false, true, true]]
    

    【讨论】:

    • 哇,谢谢你——这对我来说是一个非常酷的方式来学习如何应用一些我以前没有使用过的方法
    【解决方案2】:

    没有任何明智的考虑,一种方法是:

    ary.permutation
    .to_a.uniq
    .reject do
      |a|
      i, j = a.each_index.select{|i| a[i] == false}
      (i + 1) == j || j - 4 == i
    end
    

    【讨论】:

    • 谢谢!这真的很整洁。我不确定我是否理解您所说的“明智的考虑”是什么意思,您可以多说一些吗?
    【解决方案3】:

    解决方案 #1

    一个这样的数组的明显例子是:

    [true,false,true,false,true]
    

    如果您将一个false 与中间的true 切换,则该数组不再有效。

    如果您将一个false 与左侧或右侧true 切换,您将得到相同的数组,rotated 左侧或右侧。

    所以要获得所有可能的数组,您只需要:

    base_array = [true,false,true,false,true]
    Array.new(5){ |i| base_array.rotate(i) }
    

    它输出:

    [[true, false, true, false, true],
     [false, true, false, true, true],
     [true, false, true, true, false],
     [false, true, true, false, true],
     [true, true, false, true, false]]
    

    解决方案 #2

    蛮力解决方案将创建ary 的每个唯一排列,并检查没有连续的元素都是错误的。为了考虑换行,第一个元素被附加到数组中:

    ary = [true, true, true, false, false]
    ary.permutation.to_a.uniq.select do |a|
      (a + [a.first]).each_cons(2).all? { |x, y| x || y } 
    end
    

    如果你想变得花哨,你可以写:

    ary = [true, true, true, false, false]
    n = ary.size
    ary.permutation.to_a.uniq.select do |a|
      a.cycle.take(n+1).each_cons(2).all?(&:any?)
    end
    

    【讨论】:

    • 这太棒了,看到不同的方法来解决给我带来概念挑战的问题非常有用。感谢您提供两种不同的方法!
    【解决方案4】:

    这种递归方法直接生成排列,而不是生成大量排列并丢弃不满足规范的排列。

    代码

    def all_perms(arr_size, nbr_false)
      return nil if nbr_false > arr_size/2
      return [true]*arr_size if nbr_false.zero?
      recurse(arr_size, nbr_false, true)
    end
    
    def recurse(arr_size, nbr_false, full_arr)
      last_first = arr_size + 1 - 2*nbr_false
      (0..last_first).each_with_object([]) do |i,a|
        pre = [true]*i << false
        case nbr_false
        when 1
          a << pre + [true]*(arr_size-pre.size)
        else
          pre << true
          sub_arr_size = arr_size - pre.size - (i.zero? && full_arr ? 1 : 0)
          post = [true]*(arr_size-pre.size-sub_arr_size)
          recurse(sub_arr_size, nbr_false-1, false).each { |aa| a << pre + aa + post }
        end
      end
    end
    

    示例

    arr_size  = 5
    nbr_false = 2
    
    b = all_perms(arr_size, nbr_false)
      #=> [[false, true, false, true, true],
      #    [false, true, true, false, true],
      #    [true, false, true, false, true],
      #    [true, false, true, true, false],
      #    [true, true, false, true, false]]
    b == b.uniq
      #=> true
    b.any? { |a| a.each_cons(2).any? { |x,y| x == false && y == false} }
      #=> false
    b.any? { |a| a.first == false && a.last == false }
      #=> false
    

    arr_size  = 8
    nbr_false = 3
    
    b = all_perms(arr_size, nbr_false)
      #=> [[false, true, false, true, false, true, true, true],
      #    [false, true, false, true, true, false, true, true],
      #    [false, true, false, true, true, true, false, true],
      #    [false, true, true, false, true, false, true, true],
      #    [false, true, true, false, true, true, false, true],
      #    [false, true, true, true, false, true, false, true],
      #    [true, false, true, false, true, false, true, true],
      #    [true, false, true, false, true, true, false, true],
      #    [true, false, true, false, true, true, true, false],
      #    [true, false, true, true, false, true, false, true],
      #    [true, false, true, true, false, true, true, false],
      #    [true, false, true, true, true, false, true, false],
      #    [true, true, false, true, false, true, false, true],
      #    [true, true, false, true, false, true, true, false],
      #    [true, true, false, true, true, false, true, false],
      #    [true, true, true, false, true, false, true, false]] 
    
    b == b.uniq
      #=> true
    b.any? { |a| a.each_cons(2).any? { |x,y| x == false && y == false} }
      #=> false
    b.any? { |a| a.first == false && a.last == false }
      #=> false
    

    备注

    • 对于包含相同数量false 元素的给定大小的所有数组,有效排列是相同的。因此,我将all_perms 的参数设置为所需数组的大小和它要包含的false 元素的数量(其他元素都是true)。
    • recurse 的第三个参数full_arr 是一个布尔值,当recurseall_perms 调用时等于true,但当recurserecurse 调用时等于false。这对于避免以false 开头和结尾的排列是必要的(要避免的循环条件)。当full_arrtruei #=&gt; 0 时,正在构造的子数组的最后一个元素必须是true。在所有其他情况下,它可能是truefalse
    • 索引i 是指正在构造的第一个false 所在的子数组的索引。例如,如果arr_size #=&gt; 4nbr_false #=&gt; 2full_arr #=&gt; false,则第一个false 的索引i 可以是01。它不能是2,因为这要求最后两个元素是false

    【讨论】:

    • 不错。您知道任何通用方法来计算具有非唯一元素的数组的所有唯一排列吗?
    • @Eric,一般来说,不,但我敢肯定那里有一个权威的答案。在此处arr.uniq.size #=&gt; 2 的情况下,我们可以进行如下推理。设n 为数组大小,mfalse 元素的数量,n-mtrue 元素的数量。数组元素有n 排列。考虑其中任何一个。将每个falses 视为戴着不同颜色的帽子。我们有多少种方法可以重新排列帽子,保持阵列中的相同位置。那将是m!(续...)
    • ...对于其中的每一个,n-m trues 可以重新排列多少种方式,同时保持数组中的相同位置?那是(n-m)!。因此可以生成相同的排列m!(n-m)! 方式。因此,唯一排列的数量为n!/(m!(n-m)!)。这个表情是不是很眼熟?
    • 感谢您的解释。我不是在寻找排列的数量,而是在寻找排列本身。我发现了这篇不错的Python code,改编自 Knuth 的书。我基于此代码编写了一个 Ruby Enumerator。但是,它需要元素具有可比性,而标准 Ruby 布尔值并非如此。
    • @CarySwoveland 这真是太棒了,谢谢你给了我这么多细节来学习。我希望模仿您编写方法以允许将来更改参数的方法
    猜你喜欢
    • 2020-06-01
    • 2021-03-06
    • 2022-11-10
    • 1970-01-01
    • 2012-07-17
    • 1970-01-01
    • 1970-01-01
    • 2020-09-25
    • 2017-10-16
    相关资源
    最近更新 更多