选择模式元素匹配规则的数组排列

时间:2017-02-20 03:55:54

标签: arrays ruby

给定五个元素的数组ary

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

我想考虑最后一个位置(索引ary)绕到第一个位置(index {false,其中两个4值是非连续的0的所有排列{1}}):

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

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

4 个答案:

答案 0 :(得分:3)

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

<强>代码

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是一个布尔值,当truerecurse调用但等于all_perms时等于falserecurse调用recurse时。这对于避免以false开始和结束的排列(要避免的循环条件)是必要的。当full_arrtruei #=> 0时,正在构造的子数组的最后一个元素必须为true。在所有其他情况下,它可能是truefalse
  • 索引i是指正在构造的第一个false所在的子数组的索引。例如,如果arr_size #=> 4nbr_false #=> 2full_arr #=> false,则第一个i的索引false可以是0或{{1} }。它不能是1,因为这需要最后两个元素2

答案 1 :(得分:1)

解决方案#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

答案 2 :(得分:0)

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

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

答案 3 :(得分:0)

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

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