创建列表的许多约束,随机排列

时间:2008-09-18 15:00:27

标签: random list permutation

我需要随机列出一些排列。元素可以是任何东西,但假设它们是整数0到x-1。我想制作y列表,每个列表包含z个元素。规则是没有列表可以包含相同的元素两次,并且在所有列表中,每个元素的使用次数是相同的(或尽可能接近)。例如,如果我的元素是0,1,2,3,y是6,z是2,那么一个可能的解决方案是:

0,3
1,2
3,0
2,1
0,1
2,3

每行只有唯一的元素,没有元素使用超过3次。如果y是7,那么2个元素将被使用4次,其余3个。

6 个答案:

答案 0 :(得分:2)

这可以改进,但它似乎完成了工作(Python):

import math, random


def get_pool(items, y, z):
    slots = y*z

    use_each_times = slots/len(items)
    exceptions = slots - use_each_times*len(items)


    if (use_each_times > y or
        exceptions > 0 and use_each_times+1 > y):
        raise Exception("Impossible.")


    pool = {}
    for n in items:
        pool[n] = use_each_times

    for n in random.sample(items, exceptions):
        pool[n] += 1

    return pool

def rebalance(ret, pool, z):
    max_item = None
    max_times = None

    for item, times in pool.items():
        if times > max_times:
            max_item = item
            max_times = times


    next, times = max_item, max_times

    candidates = []
    for i in range(len(ret)):
        item = ret[i]

        if next not in item:
            candidates.append( (item, i) )


    swap, swap_index = random.choice(candidates)

    swapi = []
    for i in range(len(swap)):
        if swap[i] not in pool:
            swapi.append( (swap[i], i) )


    which, i = random.choice(swapi)

    pool[next] -= 1
    pool[swap[i]] = 1
    swap[i] = next

    ret[swap_index] = swap

def plist(items, y, z):
    pool = get_pool(items, y, z)

    ret = []
    while len(pool.keys()) > 0:
        while len(pool.keys()) < z:
            rebalance(ret, pool, z)

        selections = random.sample(pool.keys(), z)

        for i in selections:
            pool[i] -= 1
            if pool[i] == 0:
                del pool[i]

        ret.append( selections )

    return ret


print plist([0,1,2,3], 6, 2)

答案 1 :(得分:0)

好的,一种近似的方法:

1 - 随机播放列表

2 - 取y个第一个元素以形成下一行

4 - 只要列表中有数字

,就重复(2)

5 - 如果您没有足够的号码来完成列表,请重新洗牌原始列表并删除缺失的元素,确保不重新编号。

6 - 只要你需要行

,就从步骤(2)开始

我认为这应该是随机的,并且肯定会遵循您的标准。另外,您对重复元素的测试非常少。

答案 2 :(得分:0)

首先,你总是可以随意对列表进行排序,所以我们不要担心“随机排列”(硬);并且只是担心1)进行排列(简单)和2)随机化(简单)。

如果你想要“真正的”随机组,你必须接受本质上的随机化并不真正允许结果“均匀分布”的约束 - 你可能会得到这个或者你可能得到类似的 - 寻找的。如果你真的想要均匀分布,首先要均匀分布集合,然后将它们随机分组。

你必须均匀地使用集合x中的每个元素吗?从规则中不清楚我不能做出以下解释:

请注意以下内容:“在所有列表中,每个元素的使用次数相同(或尽可能接近)”

基于此标准,以及z&lt; x *,我假设您可以简单地枚举所有列表中的所有项目。因此,您会自动列出枚举到z位置的项目列表。您的示例与我的版本不符合上述规则。使用x = {0,1,2,3} y = 6和z = 2的示例,我得到: 0,1 0,1 0,1 0,1 0,1 0,1

现在我没有使用2或3,但你没有说我必须全部使用它们。如果我不得不全部使用它们并且我不在乎能够证明我“尽可能接近”甚至使用,我只会通过列表枚举所有项目,如下所示: 0,1 2,3 0,1 2,3 0,1 2,3

最后,假设我确实必须使用所有元素。要计算每个元素可以重复的次数,我只需要(y * z)/(x的计数)。这样,我不必坐下来担心如何划分列表中的项目。如果有一个余数,或者结果小于1,那么我知道我不会得到确切数量的重复,所以在这些情况下,尝试浪费计算能量以使其完美无关紧要。我认为最快的结果仍然只是按上述方式进行枚举,并使用此处的计算来说明为什么要么得到完美的结果,要么得不到完美的结果。一个花哨的算法可以从这个计算中提取出多少个位置是重复的,但是“它太长了,不适合在这里。”

*每个列表具有相同的z个元素,因此不可能制作z大于x的列表,并且仍然满足规则,即任何列表都不能包含相同的元素两次。因此,此规则要求z不能大于x。

答案 3 :(得分:0)

根据评论中的新细节,解决方案可能只是标准随机排列生成算法的实现。这里有一个关于随机置换生成算法的冗长讨论:

http://www.techuser.net/randpermgen.html

(来自Google搜索:随机排列生成)

答案 4 :(得分:0)

这适用于Ruby:

# list is the elements to be permuted
# y is the number of results desired
# z is the number of elements per result
# equalizer keeps track of who got used how many times
def constrained_permutations list, y, z
  list.uniq! # Never trust the user. We want no repetitions.
  equalizer = {}
  list.each { |element| equalizer[element] = 0 }

  results = []
  # Do this until we get as many results as desired
  while results.size < y
    pool = []
    puts pool
    least_used = equalizer.each_value.min
    # Find how used the least used element was
    while pool.size < z
      # Do this until we have enough elements in this resultset
      element = nil
      while element.nil?
        # If we run out of "least used elements", then we need to increment
        # our definition of "least used" by 1 and keep going.
        element = list.shuffle.find do |x|
          !pool.include?(x) && equalizer[x] == least_used
        end
        least_used += 1 if element.nil?
      end
      equalizer[element] += 1
      # This element has now been used one more time.
      pool << element
    end
    results << pool
  end
  return results
end

样本用法:

constrained_permutations [0,1,2,3,4,5,6], 6, 2
=> [[4, 0], [1, 3], [2, 5], [6, 0], [2, 5], [3, 6]]
constrained_permutations [0,1,2,3,4,5,6], 6, 2
=> [[4, 5], [6, 3], [0, 2], [1, 6], [5, 4], [3, 0]]
enter code here

答案 5 :(得分:0)