Python 混合两个列表

Python 混合两个列表,python,list,Python,List,我试图创建一个函数来混合python中的两个列表,或者更确切地说是将list2的元素放入list1中。要求在输出列表中,相邻两个具有相同值的元素不超过两个 例如: list1 = [1,1,1,1,1] list2 = [2,2,2,2,2] output = [1,1,2,1,2,2,1,2,1,2] 错误的输出示例: # There are more than two '1' standing next two each other output = [1,1,1,2,2,1,2,1,2,

我试图创建一个函数来混合python中的两个列表,或者更确切地说是将list2的元素放入list1中。要求在输出列表中,相邻两个具有相同值的元素不超过两个

例如:

list1 = [1,1,1,1,1]
list2 = [2,2,2,2,2]
output = [1,1,2,1,2,2,1,2,1,2]
错误的输出示例:

# There are more than two '1' standing next two each other
output = [1,1,1,2,2,1,2,1,2,2]
以下是我的解决方案:

def guyGenerator(toughGuy,softGuy):
    i = 0
    while len(softGuy) > 0:
        temp = softGuy[:1]
        while i < len(toughGuy) - 1:
            if toughGuy[i] == toughGuy[i + 1] == 2:
                toughGuy.insert(random.randint(i, i + 1), temp[0])
            i = i + 1
        softGuy = softGuy[1:]
    return toughGuy
我做错了什么

编辑1

Clodion让我把这个放在这里

结果可以是随机的,只要它们满足问题中的要求。元素的顺序并不重要,只要相邻的两个元素中不超过两个具有相同的值

编辑2

我试图通过使用Clodion解决方案创建一个iterable类来搞乱。以下是新代码:

import random

class GuyGenerator:
    def __init__(self,toughGuyList,softGuyList):
        self.toughGuyList = toughGuyList
        self.softGuyList = softGuyList
    def __iter__(self):
        return self
    def __next__(self):
        listSum = self.toughGuyList + self.softGuyList
        while True:
            res = random.sample(listSum,len(listSum))
            if not any([res[i-2]==res[i-1]==res[i] for i in range(len(listSum))]):
                break
        return res

toughGuy = ['tough','tough','tough','tough','tough','tough','tough','tough']
softGuy = ['soft','soft','soft','soft','soft','soft','soft','soft']
for guy in GuyGenerator(toughGuy,softGuy):
    print(guy)
结果非常好,除了代码执行不受限制,我不得不使用键盘中断来停止代码。在这种情况下,我做错了什么?如果能详细解释我将不胜感激,因为我是Python和迭代器的新手

编辑3

解决了迭代器问题,比我想象的要简单。事实证明,iter中返回的内容就是类在for循环中调用时返回的内容

解决方案:

def __iter__(self):    
    listSum = self.listRandom1 + self.listRandom2
    while True:
        self.res = random.sample(listSum,len(listSum))
        if not any([self.res[i-2]==self.res[i-1]==self.res[i] for i in range(len(listSum))]):
            break
    return iter(self.res)

您可以使用
random
中的
shuffle

list1=[1,1,1,1,1]
list2=[2,2,2,2,2]
import random
lst = list1+list2
print(lst)
while True:
    random.shuffle(lst)
    if not any([lst[i-2]==lst[i-1]==lst[i]for i in range(len(lst))]):
        break
print(lst)
结果:

[1, 2, 1, 1, 2, 1, 2, 2, 1, 2]
说明:我添加了两个列表并将其
suffle
。然后我重复洗牌,直到没有3个相同的连续数字。正如评论所指出的,这可能需要很长时间,但很容易限制迭代次数。
试图解释代码不起作用的原因:

def guyGenerator(toughGuy,softGuy):
    import random
    i = 0
    while len(softGuy) > 0:
        temp = softGuy[:1]
        while i < len(toughGuy)- 1:
            if toughGuy[i] == toughGuy[i + 1] == 2:
                # you insert temp[0]: it can be inserted before i
                # for lst = [0, 1, 2, 3]
                # lst.insert(0, "X") result in ["X", 0, 1, 2, 3]
                # But then, the next time, you'll test exactly the
                # same thing: because you increment i and have move all
                # the items of toughGuy one char to the right
                # and that, without reducing softGuy len.
                toughGuy.insert(random.randint(i, i + 1), temp[0])
            i = i + 1
        softGuy = softGuy[1:]
    return toughGuy

print(guyGenerator([2,2,2,2,2], [1,1,1,1,1]))
如果
randint
give
i
,则在项目前插入“X”。
增加i和,使我找到完全相同的元素:

>>> lst = [1, 2, 3, 4, 5]
>>> lst.insert(0, "X")
>>> lst
['X', 1, 2, 3, 4, 5]
>>> lst.insert(1, "X")
>>> lst
['X', 'X', 1, 2, 3, 4, 5]
>>> 
这就是问题所在,因为你仍然在同一个循环中!!! 因此,在将softGuy减少一个元素之前,可以插入多个temp[0]。是吗?

欢迎任何建议

您可以实现一个贪婪算法,该算法试图生成最常见的项 尽可能频繁(即最多两次),然后生成下一个最常见的项目 必要时

与随机洗牌搜索相比,这有两个优点:

  • 随着
    项长度的增加,贪婪算法会更快:

    In [223]: %timeit list(intermix([1]*10+[2]*5))
    10000 loops, best of 3: 39.8 µs per loop
    
    In [222]: %timeit intermix_random([1]*10+[2]*5)
    100 loops, best of 3: 6.85 ms per loop
    
  • 它可以识别何时没有解决方案,而随机洗牌搜索 如果访问的洗牌未缓存,则永远循环



您可以采用受气泡排序算法启发的方法。这将包括交换数字以打破三值连胜,直到不再需要交换。换句话说,对于每个
a、a、a、b
来说,将
b
与前面的
a
交换,使其成为
a、a、b、a

list1 = [1,1,1,1,1,1,1,1,1,1]
list2 = [2,2,2,2,2]

output   = list1+list2
swapping = True
while swapping:
    swapping = False
    for i in range(3,len(output)):
         if output[i] != output[i-1] and output[i-3:i-1] == output[i-2:i]:
             swapping = True
             output[i-1:i+1] = output[i-1:i+1][::-1] 

print(output)
[1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2]

拜托,为什么是“-1”?提前感谢。一个基于随机性的解决方案,理论上可以运行数小时,这让我很困扰,这是懒惰,这不是一个好的编码方式。我也投了反对票,以供使用。我确信我不必解释为什么这个解决方案非常非常糟糕。@unutbu的答案非常好。我很难相信你试图捍卫Bogosort是一种实用的算法,我没有看到随机结果的要求,也没有提到随机性@乌布图不仅回答了这个问题,而且给出了一个完整的答案,里面充满了极好的建议。你至少应该编辑你的答案,让它完全清楚你在使用什么样的算法。嗯,结果应该是随机的⋅… 不?@Clodion-不,我认为不需要随机结果。我不知道你从哪里得到的。@TigerhawkT3:请看我代码下面的答案。如果
列表
无法这样排列(例如
列表1=[1,1,1];列表2=[1,1,1]
),会发生什么?每个
列表
是否总是包含一个数字?@Tuan Dinh:请问您是否希望随机结果?提前谢谢。然后编辑你的问题写出来?@Clodion:是的,结果可以是随机的,只要它们满足要求
In [223]: %timeit list(intermix([1]*10+[2]*5))
10000 loops, best of 3: 39.8 µs per loop

In [222]: %timeit intermix_random([1]*10+[2]*5)
100 loops, best of 3: 6.85 ms per loop
import collections
def intermix(items, nconsecutive=2):
    counter = collections.Counter(items)
    # sort from most common to least common
    items = sorted(items, key=counter.get, reverse=True)
    N = len(items)
    count = 0
    # remember the last two values
    last = []
    for i in range(N):
        val = items[i]
        if len(last) < nconsecutive:
            if last and val == last[-1]:
                last.append(val)
            else:
                last = [val]
            counter[val] -= 1
            yield val
        else:
            # last is full; find a different value
            for j in range(i, N):
                if items[j] != last[-1]:
                    items[i], items[j] = items[j], items[i]
                    val = items[i]
                    last = [val]
                    counter[val] -= 1
                    # as items are yielded, the meaning of "most common" can change.
                    items[i+1:] = sorted(items[i+1:], key=counter.get, reverse=True)
                    yield val
                    break
            else:
                raise ValueError('No solution possible')
In [184]: list(intermix([1,1,1,1,1,2,2,2,2,2]))
Out[184]: [1, 1, 2, 2, 1, 2, 2, 1, 2, 1]

In [185]: list(intermix([1,0,1,1,2,1,0,1,1,1,2]))
Out[185]: [1, 1, 0, 1, 1, 2, 1, 1, 2, 1, 0]

In [186]: list(intermix([1,0,1,1,2,1,0,1,1,1,1,1,1,2]))
Out[186]: [1, 1, 0, 1, 1, 2, 1, 1, 2, 1, 1, 0, 1, 1]

In [187]: list(intermix([1,0,1,1,2,1,0,1,1,1,1,1,1,1,2]))
ValueError: No solution possible

In [188]: list(intermix([1,0,1,1,2,1,0,1,1,1,1,1,1,1,2], nconsecutive=3))
Out[188]: [1, 1, 1, 0, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 0]
list1 = [1,1,1,1,1,1,1,1,1,1]
list2 = [2,2,2,2,2]

output   = list1+list2
swapping = True
while swapping:
    swapping = False
    for i in range(3,len(output)):
         if output[i] != output[i-1] and output[i-3:i-1] == output[i-2:i]:
             swapping = True
             output[i-1:i+1] = output[i-1:i+1][::-1] 

print(output)
[1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2]