繁体   English   中英

我们如何在 python 中随机洗牌列表的元素?

[英]how can we riffle shuffle the elements of a list in python?

我想在不导入任何模块的情况下打乱列表的元素。 洗牌的类型是浅滩洗牌。 你想在哪里划分号码。 将列表的元素分成两部分,然后将它们交错。

如果有奇数没有。 的元素,那么后半部分应该包含额外的元素

例如:列表 = [1,2,3,4,5,6,7]

then the final list should look like [1,4,2,5,3,6,7]

只是为了好玩,递归解决方案:

def interleave(lst1, lst2):
    if not lst1:
        return lst2
    elif not lst2:
        return lst1
    return lst1[0:1] + interleave(lst2, lst1[1:])

在 Python 2.x 中按如下方式使用它(在 Python 3.x 中,使用//而不是/ ):

lst = [1,2,3,4,5,6,7]
interleave(lst[:len(lst)/2], lst[len(lst)/2:])
=> [1, 4, 2, 5, 3, 6, 7]

以上内容适用于任何长度的列表,长度是偶数还是奇数都没有关系。

listA = [1,2,3,4,5,6,7,8,9]
listLen = len(listA)/2
listB = listA[:listLen]
listC = listA[listLen:]
listD = []
num = 0
while num < listLen:
    if len(listB) >= num:
        listD.append(listB[num])
        listD.append(listC[num])
    num += 1
if len(listA)%2 != 0:
    listD.append(listC[num])
print listD

在查看了另一个答案之后,我还添加了一个递归版本,这是另一个人的答案的修订版,但更容易调用,因为您只需使用单个参数调用函数(您尝试改组的列表) 它会做其他所有事情:

def interleave(lst):
    def interleaveHelper(lst1,lst2):
        if not lst1:
            return lst2
        elif not lst2:
            return lst1
        return lst1[0:1] + interleaveHelper(lst2, lst1[1:])
    return interleaveHelper(lst[:len(lst)/2], lst[len(lst)/2:])

当你去调用它时,你可以说interleave(list)

例如:list = [1,2,3,4,5,6,7] 那么最终列表应该看起来像 [1,4,2,5,3,6,7]

这是一个应该可靠地做到这一点的函数:

def riffle(deck):
    '''
    Shuffle a list like a deck of cards.
    i.e. given a list, split with second set have the extra if len is odd
    and then interleave, second deck's first item after first deck's first item
    and so on. Thus:
    riffle([1,2,3,4,5,6,7])
    returns [1, 4, 2, 5, 3, 6, 7]
    '''
    cut = len(deck) // 2                        # floor division
    deck, second_deck = deck[:cut], deck[cut:]
    for index, item in enumerate(second_deck):
        insert_index = index*2 + 1
        deck.insert(insert_index, item)
    return deck

并对其进行单元测试...

import unittest
class RiffleTestCase(unittest.TestCase):
    def test_riffle(self):
        self.assertEqual(riffle(['a','b','c','d','e']), ['a','c','b','d','e'])
        self.assertEqual(riffle([1,2,3,4,5,6,7]), [1,4,2,5,3,6,7])

unittest.main()
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK
def riffle(deck):
    new_deck = []
    deck_1 = deck[:len(deck)//2]
    deck_2 = deck[len(deck)//2::]
    for i in range(len(deck)//2):
        new_deck.append(deck_1[i])
        new_deck.append(deck_2[i])
    if len(deck) % 2 == 1:
        new_deck.append(deck[-1])
    return new_deck


deck = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
print(riffle(deck))

通过利用 Python 中迭代器的next特性,你可以很容易地做到这一点。

您要做的第一件事是将元素分成两部分。

接下来,使用 Python 的iter函数将这两部分转换为迭代器。 你可以跳过这一步,但我发现调用next(iterable)比手动索引列表要干净得多。

最后,您将遍历列表的前半部分,并为您添加的每个元素添加后者的相应元素(调用next给出序列中的下一项)。

例如:

elements = [1,2,3,4,5,6,7]

half_point = len(elements)/2

a = iter(elements[0:half_point])
b = iter(elements[half_point: ])

result = []
for i in range(half_point):
    result.append(next(a))
    result.append(next(b))

if len(elements) % 2 != 0:
    result.append(next(b))

print result

>>> [1, 4, 2, 5, 3, 6, 7]

底部的最后一位检查列表是否为奇数。 如果是,它将最后一个元素附加到列表的末尾。

如果你有创意,你可能会通过压缩然后解包来压缩它,但我会把它留到你探索itertools时;)

您可以将输入列表分成两部分,然后使用 zip 和一些列表操作来交错项目。

n = 9
l = range(1,n+1)
a = l[:n/2]
b = l[n/2:]
c = zip(a,b)
d = list()
for p in c :
    d.extend(list(p))
if n%2==1:
    d.append(b[n/2])
print(d)
>>> ll = list(range(1,8))
>>> mid = len(ll)/2   # for Python3, use '//' operator
>>> it1 = iter(ll[:mid])
>>> it2 = iter(ll[mid:])
>>> riff = sum(zip(it1,it2), ()) + tuple(it2)
>>> riff
(1, 4, 2, 5, 3, 6, 7)

如果这是家庭作业,请准备好解释sumzip在这里的工作原理, sum的第二个参数是什么,为什么将tuple(it2)添加到末尾,以及该解决方案如何具有固有的低效率。

如果 deck 是一个列表,请编写一个执行列表推导的函数来执行洗牌:

def riffle_shuffle(deck):
    return [deck[i//2 + (i%2)*(len(deck)//2)] for i in range(len(deck))]

您可能会找到表达式i%2 ,它在偶数上计算为 0,在奇数上计算为 1,以交替访问牌组的开头和中间。

def riffle(deck: List[int]) -> List[int]:
    result = []
    mid = len(deck) // 2
    for i in range(len(deck)):
        result.append(deck[i // 2 + (i % 2) * mid])
    return result

或者,您可以分别对奇数和偶数使用 if 表达式:

def riffle(deck: List[int]) -> List[int]:
    result = []
    mid = len(deck) // 2
    for i in range(len(deck)):
        if not i % 2:
            result.append(deck[i // 2])
        else:
            result.append(deck[i // 2 + mid])
    return result

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM