【问题标题】:Loop through list until value is found then breaking?循环遍历列表直到找到值然后中断?
【发布时间】:2015-05-11 11:34:02
【问题描述】:

我有一个列表:[1,2,3,4,5,6,0,9,2],我想循环访问它。

我想为每 3 个元素创建另一个字典列表,直到达到 0 元素(即第一个字典将是 {'gold':1,'silver':2,'bronze':3}4,5,6 类似)。循环将在到达0 后终止。

所以结果列表将是:[{'gold':1,'silver':2,'bronze':3},{'gold':4,'silver':5,'bronze':6}]

作为 Python 新手并具有 PHP 背景,我将如何利用 zipmap 等函数解决此问题,或者我是否必须求助于普通的 while 循环?

【问题讨论】:

  • 你知道零总是出现在一组 3 个元素中的第一个吗?如果不应该将该三元组包含在列表中?
  • 不,零可以出现在任何地方,如果字典包含零,则将其丢弃并终止循环。
  • @VeraWang,按键的顺序呢?
  • @PadraicCunningham 如图所示。
  • @VeraWang,没问题,检查 dict 大小将始终正常工作,takewhile 也会获取所有没有 0 的列表,所以无论发生什么你都会得到正确的结果。重要的部分是字典的长度。你不能使用模

标签: python list loops


【解决方案1】:
from itertools import cycle

placings = cycle(['gold', 'silver', 'bronze'])
numbers = [1,2,3,4,5,6,0,9,2]

def zipper(numbers, placings):

    d = {}

    for n, c in zip(numbers, placings):

        if n == 0:
            break

        d[n] = c

        if n % 3 == 0:
            yield d
            d = {}

print list(zipper(numbers, placings))

【讨论】:

  • 不错的@John :) 很好地使用函数式编程!
  • @JamesMills 我将您的编辑从return d 更改为return None,因为它可能会返回部分完成的字典,这将是不好的行为。在research 之后,我同意函数可能应该显式返回一些东西。
  • 非常干净易读。我应该学习 Python 而不是 PHP。
【解决方案2】:
from itertools import takewhile, islice


def groups(l, keys, i, n):
    # lambda x: x != 0 -> take elements until we encounter any 0
    tk = takewhile(lambda x: x != i, l)
    while True:
        d = dict(zip(keys, islice(tk, n)))
        if len(d) == n: # make sure we have n keys in the dict
            yield d
        else: 
            break

keys = ['gold', 'silver', 'bronze']
print(list(groups(l,keys,0,3)))
[{'bronze': 3, 'gold': 1, 'silver': 2}, {'bronze': 6, 'gold': 4, 'silver': 5}]

takewhile

创建一个迭代器,只要谓词为真,它就会从可迭代对象中返回元素。

所以我们只取元素直到我们遇到的第一个 id = islice(tk,n) 使用 islice 从我们的 takewhile 对象中取一个 n 长度切片,然后我们从传入的键创建一个字典,创建dict 一次消耗n 元素,因此每次调用它时我们都会移动到接下来的三个元素。如果 takewhile 对象的长度不是n 的倍数,那么我们最后会有一个小于n 大小的dict,所以if len(d) == n: 会捕捉到它并打破循环,所以奇怪的是长度字典或空字典将终止while。

如果您允许使用少于三个键的字典:

from itertools import takewhile, islice,chain

def groups(l, keys, i, n):
    tk = takewhile(lambda x: x != i, l)
    return (dict(zip(keys, chain(islice(tk, n - 1),(i,)))) for i in tk)

输出:

In [5]: l = [1, 2, 3, 4, 5, 6, 7, 11, 6, 9, 0, 2]

In [6]: list(groups(l,['gold', 'silver', 'bronze'],0,3))
Out[6]: 
[{'bronze': 1, 'gold': 2, 'silver': 3},
 {'bronze': 4, 'gold': 5, 'silver': 6},
 {'bronze': 7, 'gold': 11, 'silver': 6},
 {'gold': 9}]

islice(tk, n - 1) 从我们的 takewhile 对象 len n - 1 中获取一个切片,我们将它和i 链接起来,所以我们每次都得到n 元素。

或者使用filter过滤掉少于3个key的dict:

def groups(l, keys, i, n):
    tk = takewhile(lambda x: x != i, l)
    return filter(lambda x: len(x) == n, (dict(zip(keys, chain(islice(tk, n - 1),(i,)))) 
                                          for i in tk))

删除较短的字典:

In [8]: list(groups(l,['gold', 'silver', 'bronze'],0,3))
Out[8]: 
[{'bronze': 1, 'gold': 2, 'silver': 3},
 {'bronze': 4, 'gold': 5, 'silver': 6},
 {'bronze': 7, 'gold': 11, 'silver': 6}]

这与之前的相同,我们只是从末尾过滤任何可能的奇数长度字典。对于 python2 使用 itertools.ifilter 而不是过滤器。

【讨论】:

  • 在你的第一个 groups 函数中,为什么它没有返回语句?
  • @VeraWang,因为我们在每个 dict 的 len 等于 n 时让步,否则我们只是打破循环,因为我们最后有一个没有三个元素的 dict第一个 0 位于一个不是 3 的倍数的索引处。您可以遍历 groups(l,keys,0,3)) 并即时获取每个字典,您不必调用 list 并将整个字典列表存储在内存中,这就是使用生成器的优势。
  • 如果你想要有 n 键的字典,你需要检查每个键的长度,答案第二部分的输入将在末尾留下一个奇数长度的字典
  • 我明白了,奇怪的是我已经尝试运行你的代码:ideone.com/WzZGi5,它会导致这里和我的机器上的无限循环。
  • @VeraWang,是的,抱歉,我没有添加任何解释,我只是想确保我们涵盖了所有情况,itertools 库绝对值得花一些时间熟悉。
【解决方案3】:

简单!用一个简单的函数,一个数据结构和简单的迭代:

示例:

from collections import defaultdict


def f(xs, labels=("gold", "silver", "bronze")):
    d = defaultdict(int)
    n = 0
    for i, x in enumerate(xs):
        if x == 0:  # break if we see a 0
            return d

        d[labels[n]] += i  # update our counts

        # cycle through gold/silver/bronze (labels)
        n += 1
        if n % 3 == 0:
            n = 0

    return d


xs = [1, 2, 3, 4, 5, 6, 0, 9, 2]
d = f(xs)
print d

输出:

$ python foo.py 
defaultdict(<type 'int'>, {'bronze': 7, 'silver': 5, 'gold': 3})

【讨论】:

  • 我不确定是否要更改我的响应以根据@John 的响应生成一系列 dict(s) :) 看来这就是这里的想法!
【解决方案4】:

首先,您需要将较大的列表分成与列表medals 相同大小的较小列表,以使zip() 函数正常工作,并且0 在列表中的位置应位于位置可以被medals 列表的长度整除,否则较小列表中的最后一个列表将具有较少数量的元素。

listOfDictionary = []
lst = [1,2,3,4,5,6,0,9,2]

ind = lst.index(0)   #Tells where to break the iteration loop.

medals = ["gold", "silver", "bronze"]

if ind%3==0:

    newlst = [lst[i: i+3]for i in xrange(0,ind,3)]
    #newlst = [[1, 2, 3], [4, 5, 6]]

    for lsst in newlst:
        listOfDictionary.append(dict(zip(medals, lsst)))


print listOfDictionary
>>> [{'bronze': 3, 'silver': 2, 'gold': 1}, {'bronze': 6, 'silver': 5, 'gold': 4}]

【讨论】:

    【解决方案5】:

    在列表的情况下使用列表推导然后使用循环

    In [61]: mykeys
    Out[61]: [1, 2, 3, 4, 5, 6, 0, 9, 2]
    
    In [63]: mykeys1=[i for i in mykeys[:-1 if 0 not in mykeys else mykeys.index(0)]]
    
    In [64]: myvalues
    Out[64]: ['gold', 'silver', 'bronze']
    
    In [66]: myvalues1=cycle(myvalues)
    
    In [67]: mydict=dict(zip(mykeys1,myvalues1))
    
    In [68]: mydict
    Out[68]: {1: 'gold', 2: 'silver', 3: 'bronze', 4: 'gold', 5: 'silver', 6: 'bronze'}
    In [69]: [dict(mydict.items()[i:i+3]) for i in range(0,len(mykeys1),3)]
    Out[69]: [{1: 'gold', 2: 'silver', 3: 'bronze'}, {4: 'gold', 5: 'silver', 6: 'bronze'}]
    

    【讨论】:

    • 这会创建一个字典
    • @Padraic Cunningham 谢谢..我认为问题已修改..我没有看到..谢谢...顺便说一句,您的回答是最优雅的,我会选择它作为回答者
    猜你喜欢
    • 2019-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-14
    • 1970-01-01
    • 1970-01-01
    • 2017-03-09
    相关资源
    最近更新 更多