简体   繁体   English

将项目列表随机分组,但某些项目不能在同一组中

[英]Group list of items randomly, but some items cannot be in same group

I have a list of names that I want to put into n-number of groups. 我有一个要放入n个组的名称列表。 I can do that easily. 我可以轻松做到。 However, my issue is, that some of the items cannot be grouped together no matter what. 但是,我的问题是,某些项目无论如何都无法组合在一起。 Is there a simple solution to this ? 有一个简单的解决方案吗?

This is how I do it now: 我现在是这样的:

import random

name_list = ["Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7"]
n = 2

random.seed(4)
random.shuffle(name_list)

test = [name_list[i:i + n] for i in xrange(0, len(name_list), n)]

print(test)

So from this, I will get 4 groups, randomly shuffled, with only 1 in the last group (that is okay). 因此,从中,我将得到随机分组的4个组,最后一组中只有1个(没关系)。 However, let's say that Item1 and Item5 can't end up together. 但是,假设Item1Item5不能一起结束。 How would I dot that ? 我要如何点呢?

Here we get groups or "chunks" for randomly distributed items. 在这里,我们得到了随机分配的物品的组或“块”。

Given 给定

import random
import itertools as it

import more_itertools as mit


random.seed(4)
n = 2
name_list = ["Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7"]
blacklist = ["Item1", "Item5"]

Code

def get_random_groups(lst, size=2, blacklist=None):
    """Return distributed items among `m` groups of lists."""
    if blacklist is None:
        blacklist = []

    # Compute number of chunks
    length = (len(lst))
    if length % 2 == 0:
        m = length//size
    else:
        m = (length+1)//size

    # Edge cases
    if len(blacklist) > m:
        raise ValueError("Black-list is too long.  Must be < number of chunks.")
    if not set(blacklist).issubset(set(lst)):
        raise ValueError("Black-list is not a subset of the main list.")

    # Resize list
    remnant_list = list(set(lst) - set(blacklist))
    random.shuffle(remnant_list)

    # Build chunks and distribute (blacklist first)
    chunks = [list(c) for c in mit.distribute(m, blacklist)]
    random.shuffle(chunks)

    for chunk in chunks[:]:
        while len(chunk) < size:
            try:
                chunk += [remnant_list.pop(-1)]
            except IndexError:
                return chunks

Demo 演示版

# Without blacklist
get_random_groups(name_list, size=n)
# Out: [['Item5', 'Item1'], ['Item3', 'Item6'], ['Item7', 'Item2'], ['Item4']]

# With blacklist
get_random_groups(name_list, size=n, blacklist=blacklist)
# [['Item2', 'Item6'], ['Item1', 'Item3'], ['Item5', 'Item7'], ['Item4']]

# Invalid blacklist
blacklist = "Item1 Item3 Item 5 Item6 Item7".split()  
get_random_groups(name_list, size=n, blacklist=blacklist)
# ValueError: Blacklist is too long.  Must be < number of chunks.

# Invalid blacklist
blacklist = "Item1 Item9".split()  
get_random_groups(name_list, size=n, blacklist=blacklist)
# ValueError("Black-list is not a subset of the main list.")

Details 细节

  • The number of chunks is computed based on lists of even or odd length. 块的数量是根据偶数或奇数长度的列表计算的。
  • Edge cases are tested (optional). 边缘盒已经过测试(可选)。
  • Items in the blacklist will be distributed among chunks first. blacklist项目将首先在大块之间分配。 Therefore, those items must be removed from the list of remaining elements ( remnant_list ). 因此,必须从其余元素列表( remnant_list )中删除这些项目。
  • more_itertools.distribute is a third-party tool that facilitates chunking and distributing items among m number of chunks. more_itertools.distribute是一种第三方工具,可促进在m个块之间进行 分配分配 You can optionally implement your own algorithms to accomplish these two tasks. 您可以选择实现自己的算法来完成这两项任务。
  • A random remnant item is added to a shuffled chunk unless the size of the chunk is satisfied. 除非满足块的size ,否则将随机余项添加到随机的块中。 This double shuffling ensure items are placed randomly. 这种双重改组可确保物品随机放置。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM