【问题标题】:Reordering a list to meet conditions重新排序列表以满足条件
【发布时间】:2020-03-05 11:35:51
【问题描述】:

对于大学的某门课程,学生需要每周在课堂上展示主题。学生每周以随机顺序出现。

函数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的代码?

【问题讨论】:

  • 说实话 - 你的代码有点太长了,我现在无法理解它的想法。但是,这个问题很有趣,我想知道第 n 周和第 n+2 周的大等式是故意的还是应该优化的缺点。
  • 这能回答你的问题吗? How to randomize a list to meet conditions

标签: python list sorting optimization permutation


【解决方案1】:

我的做法是这样的:

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']

编辑: 我刚刚意识到第一行应该是未更改的原始列表。因此我评论了第一次洗牌;这样您就可以在需要时轻松取回它。

【讨论】:

  • 谢谢。请记住,输出中的第一个列表应该始终是原始输入列表,然后根据条件随机化版本。
猜你喜欢
  • 1970-01-01
  • 2021-06-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-02
  • 2011-11-16
  • 1970-01-01
相关资源
最近更新 更多