【问题标题】:Array combinatorics数组组合
【发布时间】:2021-03-19 04:05:12
【问题描述】:

我正在使用 Ruby 2.7。

我有一个 Array,它的元素是以下三种之一:String 或 Integer,或者偶尔是另一个带有一对元素的 Array(这次只有 Strings 或 Integers)。根据我的问题的定义,数组没有进一步的嵌套级别。

例子:

w = [1, 2, 'b', 4]
x = [[2, 'r'],[2, 'g']]
y = [[2, 'w']]
z = ['u', 6, [2, 'r']]

问题的上下文是内部数组表示用于外部数组的可选替代项。我正在寻找所有可能的方法来从每个内部数组中选择一个元素(如果存在),然后将该元素替换到外部数组中。

例子:

f(w) = [ [1, 2, 'b', 4] ]
f(x) = [ [2, 2], [2, 'g'], ['r', 2], ['r', 'g'] ]
f(y) = [ [2], ['w'] ]
f(z) = [ ['u', 6, 2], ['u', 6, 'r'] ]

每个选择(每个解决方案的内部数组)中的元素顺序无关紧要。输出中解决方案的顺序也无关紧要。

我可以强行选择/拒绝、转换和使用 Array#product;但我正在寻找一种尽可能简洁和优雅的方法。

【问题讨论】:

  • 请用更准确的语言重新表述您的问题。 xf(x) 的值与 我正在寻找所有可能的方法从每个内部数组中选择一个元素(如果存在)并将该元素替换到外部数组中的措辞不一致 -- 两者甚至没有远程兼容。
  • 如果你可以强行回答,发布该代码,也许我们可以优化它。强迫我们从头开始重新发明解决方案是没有建设性的。

标签: arrays ruby cartesian-product


【解决方案1】:

问题中给出的规则不准确且不完整,因此我已尽力推断它们是什么。

代码

def doit(arr)
  if arr.size == 1
    e = arr.first
    return e.is_a?(Array) ? (arr.map { |f| [f] }) : arr
  end
  (first, *rest), other = arr.partition { |e| e.is_a?(Array) }
  return [arr] if first.nil?
  prod = first.product(*rest)
  return prod if other.empty?
  prod.flat_map { |a| other.map { |e| [e, *a] } }
end

请参阅Enumerable#partitionArray#productEnumerable#flat_map

示例

doit [1, 2, 'b', 4]
  #=> [[1, 2, "b", 4]] 
doit [[2, 'r'],[2, 'g']]
  #=> [[2, 2], [2, "g"], ["r", 2], ["r", "g"]] 
doit [:a, [2, 'r'], :b, [2, 'g']]
  #=> [[:a, 2, 2], [:b, 2, 2], [:a, 2, "g"], [:b, 2, "g"],
  #    [:a, "r", 2], [:b, "r", 2], [:a, "r", "g"], [:b, "r", "g"]] 
doit [[2, 'w']]
  #=> [[[2, "w"]]] 
doit ['u', 6, [2, 'r']]
  #=> [["u", 2], [6, 2], ["u", "r"], [6, "r"]] 
doit [:a, [2, 3], :b, :c, [4, 5], :d, [6, 7]]
  #=> [[:a, 2, 4, 6], [:b, 2, 4, 6], [:c, 2, 4, 6], [:d, 2, 4, 6],
  #    [:a, 2, 4, 7], [:b, 2, 4, 7], [:c, 2, 4, 7], [:d, 2, 4, 7],
  #    [:a, 2, 5, 6], [:b, 2, 5, 6], [:c, 2, 5, 6], [:d, 2, 5, 6],
  #    [:a, 2, 5, 7], [:b, 2, 5, 7], [:c, 2, 5, 7], [:d, 2, 5, 7],
  #    [:a, 3, 4, 6], [:b, 3, 4, 6], [:c, 3, 4, 6], [:d, 3, 4, 6],
  #    [:a, 3, 4, 7], [:b, 3, 4, 7], [:c, 3, 4, 7], [:d, 3, 4, 7],
  #    [:a, 3, 5, 6], [:b, 3, 5, 6], [:c, 3, 5, 6], [:d, 3, 5, 6],
  #    [:a, 3, 5, 7], [:b, 3, 5, 7], [:c, 3, 5, 7], [:d, 3, 5, 7]]

请注意,doit [[2, 'w']] 的返回值与问题中给出的不同。

说明

步骤如下。

arr = [:a, [2, 'r'], :b, [2, 'g']]

(first, *rest), other = arr.partition { |e| e.is_a?(Array) }
  #=> [[[2, "r"], [2, "g"]], [:a, :b]] 

Ruby 将array decomposition 应用于上述表达式以获得firstrestother 的值:

first
  #=> [2, "r"] 
rest
  #=> [[2, "g"]] 
other
  #=> [:a, :b] 

继续,因为first.nil? #=> falsereturn [arr] if first.nil?,我们不返回。下一个:

prod = first.product(*rest)
  #=> [[2, 2], [2, "g"], ["r", 2], ["r", "g"]]

other.empty? #=> false in return prod if other.empty? 所以我们不会返回。

我可以通过在代码中插入puts 语句并运行它来最好地解释剩余的计算。

prod.flat_map do |a|
  puts "a = #{a}"
  other.map do |e|
    puts "  e = :#{e}"
    puts "    [e, *a] = #{[e, *a]}"
    [e, *a]
  end
end
  #=> [[:a, 2, 2], [:b, 2, 2], [:a, 2, "g"], [:b, 2, "g"],
  #    [:a, "r", 2], [:b, "r", 2], [:a, "r", "g"], [:b, "r", "g"]] 

显示如下。

a = [2, 2]
  e = :a
    [e, *a] = [:a, 2, 2]
  e = :b
    [e, *a] = [:b, 2, 2]
a = [2, "g"]
  e = :a
    [e, *a] = [:a, 2, "g"]
  e = :b
    [e, *a] = [:b, 2, "g"]
a = ["r", 2]
  e = :a
    [e, *a] = [:a, "r", 2]
  e = :b
    [e, *a] = [:b, "r", 2]
a = ["r", "g"]
  e = :a
    [e, *a] = [:a, "r", "g"]
  e = :b
    [e, *a] = [:b, "r", "g"]

【讨论】:

    猜你喜欢
    • 2011-08-12
    • 2017-11-14
    • 1970-01-01
    • 1970-01-01
    • 2022-01-22
    • 2010-11-28
    • 2011-04-14
    • 2010-09-18
    • 2011-10-08
    相关资源
    最近更新 更多