Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/319.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 强制执行;没有2个相同的连续元素“;在随机列表生成中_Python_Algorithm_List_Random_Rules - Fatal编程技术网

Python 强制执行;没有2个相同的连续元素“;在随机列表生成中

Python 强制执行;没有2个相同的连续元素“;在随机列表生成中,python,algorithm,list,random,rules,Python,Algorithm,List,Random,Rules,我有一组4个字符串,并希望生成一个包含16个元素的列表,但通过强制执行规则(或获得与强制执行此类规则相同的结果),将永远不会在结果列表中的两个连续位置重复相同的元素 作为一名Python新手,我检查了random库中的不同方法,发现了许多不同且有用的方法来做类似的事情(random.shuffle几乎可以做到),但没有一种方法能够满足我的特殊需要 我应该使用什么数据格式和方法?伪代码算法: 对于n中的i(n是所需元素的数量) 生成下一个元素 如果与上一个元素相同,请重复2 使用random.ch

我有一组4个字符串,并希望生成一个包含16个元素的列表,但通过强制执行规则(或获得与强制执行此类规则相同的结果),将永远不会在结果列表中的两个连续位置重复相同的元素

作为一名Python新手,我检查了random库中的不同方法,发现了许多不同且有用的方法来做类似的事情(random.shuffle几乎可以做到),但没有一种方法能够满足我的特殊需要

我应该使用什么数据格式和方法?

伪代码算法:

  • 对于n中的i(n是所需元素的数量)
  • 生成下一个元素
  • 如果与上一个元素相同,请重复2
  • 使用
    random.choice
    从元素列表中随机选取一个元素

    下面是一个概念验证Python代码:

    import random
    sources = ['a', 'b', 'c', 'd']      # you said 4 strings
    result = [random.choice(sources)]
    
    while len(result) < 16:             # you said you need 16 elements    
        elem = random.choice(sources)
        if elem != result[-1]:
            result.append(elem)
    
    随机导入
    sources=['a','b','c','d']#你说的是4个字符串
    结果=[随机选择(来源)]
    而len(result)<16:#你说你需要16个元素
    elem=随机选择(来源)
    如果元素!=结果[-1]:
    结果追加(elem)
    
    此代码是为清晰而优化的,而不是为了简洁、聪明或速度。

    相当严重地滥用了:


    它使用
    islice()
    count()
    为基础获取无限生成器的前16个元素,使用
    groupby()
    折叠相等的相邻元素。

    这是Eli的修订版本,它不会对元素施加暴力,希望不会缺乏清晰度:

    import random
    
    # 4 strings
    sources = ['a', 'b', 'c', 'd']
    
    # convert them to set
    input = set(sources)
    
    # choose first element
    output = [random.choice(input)]
    
    # append random choices excluding previous element till required length
    while len(output) < 16:
        output.append(random.choice(input - set(output[-1:])))
    
    随机导入
    #4串
    来源=['a'、'b'、'c'、'd']
    #将它们转换为set
    输入=设置(源)
    #选择第一个元素
    输出=[随机选择(输入)]
    #附加随机选择,不包括上一个元素,直到所需长度
    当len(输出)<16时:
    output.append(random.choice(输入集(输出[-1:]))
    
    有关更通用的解决方案,您可以求助于

    给定输入的任意iterable(例如:您的四个输入字符串),以下生成器将从该列表中生成无限多个选项,没有两个并排元素是相同的:

    import random
    def noncontiguous(inputs):
      last = random.choice(inputs)
      yield last
      while True:
        next = random.choice(inputs)
        if next != last:
          last = next
          yield next
    
    然后,您可以使用列表理解或基本for循环来获得该无限序列的16个元素子集:

    >>> gen = noncontiguous(['a', 'b', 'c', 'd'])
    >>> [gen.next() for i in range(16)]
    ['c', 'b', 'c', 'b', 'a', 'c', 'b', 'c', 'd', 'a', 'd', 'c', 'a', 'd', 'b', 'c']
    
    更有趣的是,您可以继续使用相同的生成器对象来创建更多的非连续元素

    >>> for i in range(8):
    ...   gen.next()
    ...
    'b'
    'c'
    'd'
    'c'
    'b'
    'd'
    'a'
    'c'
    
    Zart的代码修改为(a)工作和(b)预计算集合减法:

    import random
    
    def setsub():
        # 4 strings
        sources = ['a', 'b', 'c', 'd']
    
        # convert them to set
        input = set(sources)
        subs = {}
        for word in sources:
            subs[word] = list(input - set([word]))
    
        # choose first element
        output = [random.choice(sources)]
    
        # append random choices excluding previous element till required length
        while len(output) < 16:
            output.append(random.choice(subs[output[-1]]))
        return output
    
    随机导入
    def setsub():
    #4串
    来源=['a'、'b'、'c'、'd']
    #将它们转换为set
    输入=设置(源)
    subs={}
    来源中的单词:
    subs[word]=列表(输入集([word]))
    #选择第一个元素
    输出=[随机选择(源)]
    #附加随机选择,不包括上一个元素,直到所需长度
    当len(输出)<16时:
    output.append(random.choice(subs[output[-1]]))
    返回输出
    
    只要有可能,您应该在发布代码示例之前尝试执行它们:
    random.choice()
    不能将集合作为其输入。当你在第一次调用中使用源代码并在第二次调用中将集合减法转换为列表时,我会使它比Eli的答案慢10%。如果有超过4根弦,我预计它会很快变得更糟。然而,如果你预先计算列表减法,这会比Eli的答案快得多:(我得到:Eli:50uS,Zart:55uS,预计算:39uS)如果你真的担心性能,你可以尝试随机选择一个索引而不是一个元素。第一个索引是从
    0
    len(源)-1(含),后续索引是从
    0
    len(源)-2(含),但如果所选索引大于或等于上一个索引,则向其添加1。所以你没有乱搞很多不同的收藏品。@Duncan啊,我的错,我还没有检查我的样品是否有效。我有点希望random.choice()可以在集合上工作。与重新尝试错误选择的版本相比,这是一个典型的速度/空间权衡。随着选择数量的增加,Eli的版本可能会更有效率。@Zart,我完全同意。我应该说我只是把它作为一个答案发布,因为它不适合我对你答案的评论。随着选择数量的增加,Eli的答案很快就会胜出,或者Steve Jessop对你的答案发表评论的技巧也会很快,但可能会让人困惑(我不得不读了三遍以确保它有效)。
    
    import random
    
    def setsub():
        # 4 strings
        sources = ['a', 'b', 'c', 'd']
    
        # convert them to set
        input = set(sources)
        subs = {}
        for word in sources:
            subs[word] = list(input - set([word]))
    
        # choose first element
        output = [random.choice(sources)]
    
        # append random choices excluding previous element till required length
        while len(output) < 16:
            output.append(random.choice(subs[output[-1]]))
        return output