重新排列列表以符合条件

问题描述 投票:0回答:1

[在一所大学的某门课程中,要求学生每周上课主题演讲。学生每周随机出现。

函数presOrder应该接收两个参数,(1)代表演示文稿数周的正整数n,以及(2)仅在第一次演示文稿时必须保留的名称列表。该函数返回一周的展示顺序的列表清单。每个列表以完全随机的顺序包含给定名称,以确保名称的顺序与前一周的顺序不同,并且每个名称的位置与前一周的顺序不同。顺序不同意味着上周之前和之后的名称在下周应该不同。

import random
import itertools

def notRandom(lst, plst, no):
    result = True
    for i in range(no-1):
        result = result and (lst[i] == plst[i+1])
    result = result and (lst[no-1] == plst[0])
    if result:
        return True
    result = True
    for i in range(1,no):
        result = result and (lst[i] == plst[i-1])
    result = result and (lst[0] == plst[no-1])
    if result:
        return True
    return False


# My attempt
def presOrder(n, namelst):
    permutation = itertools.permutations(namelst)
    rand = [] + [namelst]
    prev = namelst
    for lst in permutation:
        if not(notRandom(lst, prev, len(namelst))) and len(rand) < n:
            rndom = True
            for i in range(len(namelst)):
                if not(lst[i] == prev[i]):
                    rndom = rndom and True
                else:
                    rndom = rndom and False
            if rndom:
                rand += [lst]
                prev = lst[:]
        else:
            continue
    return rand


names = ['Abi Jones', 'Bob King', 'Carl Llewellyn', 'Danielle McIntosh', 'Earl Newell', 'Frank Olephante', 'George Brown', 'Harry Zephers']

#example
>>> print(presOrder(5, names))
>>> [['Abi Jones', 'Bob King', 'Carl Llewellyn', 'Danielle McIntosh', 'Earl Newell', 'Frank Olephante', 'George Brown', 'Harry Zephers'], ('Bob King', 'Abi Jones', 'Danielle McIntosh', 'Carl Llewellyn', 'Frank Olephante', 'Earl Newell', 'Harry Zephers', 'George Brown'), ('Carl Llewellyn', 'Bob King', 'Abi Jones', 'Danielle McIntosh', 'Earl Newell', 'Frank Olephante', 'George Brown', 'Harry Zephers'), ('Danielle McIntosh', 'Abi Jones', 'Bob King', 'Carl Llewellyn', 'Frank Olephante', 'Earl Newell', 'Harry Zephers', 'George Brown'), ('Earl Newell', 'Bob King', 'Abi Jones', 'Danielle McIntosh', 'Carl Llewellyn', 'Frank Olephante', 'George Brown', 'Harry Zephers')]

该代码似乎可以正常工作,但是我需要对其进行更多测试。同时,如何优化presOrder的代码?

python list sorting optimization permutation
1个回答
0
投票

我的方法是这样的:

import random

def test_positions(L1, L2):
    return any(a==b for a, b in zip(L1, L2))

def neighbours(L):
    return [set([a, b]) for a, b in zip(L[:-1], L[1:])]

def test_neighbours(L1, L2):
    return any(nb in neighbours(L2) for nb in neighbours(L1))

def pres_order(n, L):
    result = [names[:]]
#   random.shuffle(result[0])    # only needed for reording first row
    for i in range(1, n):
        result.append(names[:])
        random.shuffle(result[-1])
        while test_positions(result[-1], result[-2]) or test_neighbours(result[-1], result[-2]):
            random.shuffle(result[-1])
    return result

想法是首先创建名称列表的((随机重新排序(随机)))版本。然后添加下一个经过改组的版本-但要反复进行改组,直到满足您的两个要求。追加到列表的长度== n。

这两个要求在test_...功能中实现。我认为关于职位的第一个是自我解释。第二个检查是否最后一行的任何邻居在最后一行中也作为邻居出现。为了实现这一点,有一个辅助函数来创建邻居对的列表。

请注意,相邻定义中的set函数将防止相邻行中的相邻名称对独立于其顺序。如果只想防止一对的精确复制(例如,应允许[...'E', 'G',... ] [...'G', 'E',... ]之后但不允许[...'E', 'G',... ]之后),则可以简单地将set函数保留下来。


示例:

names = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
for l in pres_order(5, names):
    print(l)

# ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
# ['G', 'B', 'H', 'E', 'C', 'F', 'A', 'D']
# ['H', 'C', 'B', 'A', 'E', 'D', 'F', 'G']
# ['C', 'F', 'E', 'H', 'A', 'G', 'B', 'D']
# ['G', 'H', 'B', 'F', 'D', 'A', 'E', 'C']

编辑:我只是意识到第一行应该是未更改的原始列表。因此,我评论了第一次洗牌;因此您可以根据需要轻松将其取回。

© www.soinside.com 2019 - 2024. All rights reserved.