Python 重新排列列表以满足条件

Python 重新排列列表以满足条件,python,list,sorting,optimization,permutation,Python,List,Sorting,Optimization,Permutation,对于大学的某门课程,学生们每周都要在课堂上就主题进行演讲。学生们每周按随机顺序出席 函数presOrder应该接收两个参数,(1)一个正整数n表示演示的周数,以及(2)按顺序排列的名称列表,必须仅为第一次演示保留该列表。函数返回周的演示顺序列表;每个列表都以完全随机的顺序包含给定的名称,确保名称的顺序与前一周不同,并且每个名称的位置与前一周不同。不同的顺序意味着前一周的前后名称在下一周不应相同 import random import itertools def notRandom(lst,

对于大学的某门课程,学生们每周都要在课堂上就主题进行演讲。学生们每周按随机顺序出席

函数
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')]
随机导入
进口itertools
def notRandom(lst、plst、no):
结果=真
对于范围内的i(no-1):
结果=结果和(lst[i]==plst[i+1])
结果=结果和(lst[no-1]==plst[0])
如果结果为:
返回真值
结果=真
对于范围内的i(1,否):
结果=结果和(lst[i]==plst[i-1])
结果=结果和(lst[0]==plst[no-1])
如果结果为:
返回真值
返回错误
#我的尝试
def预订单(n,名称LST):
置换=itertools.置换(namelst)
兰德=[]+[namelst]
prev=namelst
对于排列中的lst:
如果不是(非随机(lst、prev、len(namelst))和len(rand)>>打印(预订单(5个,名称))
>>>[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'))

代码似乎可以正常工作(有些),但我需要对其进行更多的测试。同时,我如何优化
预排序的代码?

我的方法如下:

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

这两个要求在
测试功能中实现。
关于职位的第一个问题,我认为是自我解释。
第二个检查最后一行的任何邻居是否也显示为最后一行的邻居。
为了实现这一点,有一个helper函数来创建相邻对的列表

请注意,相邻定义中的
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']

编辑:
我刚刚意识到第一行应该是未更改的原始列表。因此,我对第一行进行了注释;因此,如果需要,您可以很容易地将其取回。

老实说,您的代码太长了,我目前无法理解其想法。然而,问题很有趣,我想知道,如果第n周的大相等性nd n+2是故意的,或者是一个缺点,仍然需要优化。这是否回答了您的问题?谢谢。请记住,输出中的第一个列表应始终是原始输入列表,然后随机版本应根据条件进行调整。