使用Ruby产生多集的分区

时间:2017-02-13 23:08:46

标签: arrays ruby set partitioning yield

我想获得multiset的所有可能的分区(一个集合的不相交的子集,其中union是原始集合)(一些元素是相同的并且彼此不可区分)。

更简单的情况是,人们想要产生一个简单集的分区,其中没有具有多重性的元素,换句话说,所有元素都是不同的。对于这种情况,我在StackOwerflow上发现了这个Ruby代码非常有效,因为它不存储所有可能的分区,而是将它们生成块:

def partitions(set)
  yield [] if set.empty?
  (0 ... 2 ** set.size / 2).each do |i|
    parts = [[], []]
    set.each do |item|
      parts[i & 1] << item
      i >>= 1
    end
    partitions(parts[1]) do |b|
      result = [parts[0]] + b
      result = result.reject do |e|
        e.empty?
      end
      yield result
    end
  end
end

示例:

partitions([1,2,3]){|e| puts e.inspect}

输出:

[[1, 2, 3]]
[[2, 3], [1]]
[[1, 3], [2]]
[[3], [1, 2]]
[[3], [2], [1]]

由于集[1,2,3]有5种不同的分区(无论如何都是贝尔数:https://en.wikipedia.org/wiki/Bell_number

然而,实际上是多重集的另一个集包含具有多重性的元素,那么上面的代码当然不起作用:

partitions([1,1,2]){|e| puts e.inspect}

输出:

[[1, 1, 2]]
[[1, 2], [1]] *
[[1, 2], [1]] *
[[2], [1, 1]]
[[2], [1], [1]]

可以看到两个相同的分区,用*表示,应该只产生一次。

我的问题是:我如何修改def partitions()方法以使用多重集合,或者如何以有效的方式过滤掉相同的分区,重复?那些相同的分区是否总是以连续的方式相互跟随?

我的目标是将具有不同宽高比的图像组织成蒙太奇,蒙太奇的图片行将是那些设置的分区。我想在可能的分区中最小化图片行之间的高度差异(或等效的标准偏差),但很多时候有相同宽高比的图片,这就是我尝试处理多重集合的原因。

不是分区而是多重集的powersets(所有可能的子集),通过简单的memoization过滤掉重复项:

Video thumbnail
Montage optimization by backtracking on YouTube

1 个答案:

答案 0 :(得分:2)

您可以将其放入数组并使用uniq

arr = []
partitions([1,1,2]) { |e| arr << e }

puts arr.to_s
#-> [[[1, 1, 2]], [[1, 2], [1]], [[1, 2], [1]], [[2], [1, 1]], [[2], [1], [1]]]

puts arr.uniq.to_s
#-> [[[1, 1, 2]], [[1, 2], [1]], [[2], [1, 1]], [[2], [1], [1]]]