简体   繁体   English

Python 习语:列表理解与项目限制

[英]Python idiom: List comprehension with limit of items

I'm basically trying to do this (pseudo code, not valid python):我基本上是在尝试这样做(伪代码,不是有效的python):

limit = 10
results = [xml_to_dict(artist) for artist in xml.findall('artist') while limit--]

So how could I code this in a concise and efficient way?那么我怎样才能以简洁有效的方式编写代码呢? The XML file can contain anything between 0 and 50 artists, and I can't control how many to get at a time, and AFAIK, there's no XPATH expression to say something like "get me up to 10 nodes". XML 文件可以包含 0 到 50 个艺术家之间的任何内容,我无法控制一次获取多少个,而且 AFAIK,没有 XPATH 表达式可以说“让我最多 10 个节点”。

Thanks!谢谢!

Are you using lxml ?你在使用lxml吗? You could use XPath to limit the items in the query level, eg您可以使用 XPath 来限制查询级别中的项目,例如

>>> from lxml import etree
>>> from io import StringIO
>>> xml = etree.parse(StringIO('<foo><bar>1</bar><bar>2</bar><bar>4</bar><bar>8</bar></foo>'))
>>> [bar.text for bar in xml.xpath('bar[position()<=3]')]
['1', '2', '4']

You could also use itertools.islice to limit any iterable , eg您还可以 使用itertools.islice来限制任何可迭代的,例如

>>> from itertools import islice
>>> [bar.text for bar in islice(xml.iterfind('bar'), 3)]
['1', '2', '4']
>>> [bar.text for bar in islice(xml.iterfind('bar'), 5)]
['1', '2', '4', '8']

Assuming that xml is an ElementTree object, the findall() method returns a list, so just slice that list:假设xml是一个ElementTree对象, findall()方法返回一个列表,因此只需对该列表进行切片:

limit = 10
limited_artists = xml.findall('artist')[:limit]
results = [xml_to_dict(artist) for artist in limited_artists]

For everyone else who found this question because they were trying to limit items returned from an infinite generator:对于发现此问题的其他所有人,因为他们试图限制从无限生成器返回的项目:

from itertools import takewhile
ltd = takewhile(lambda x: x[0] < MY_LIMIT, enumerate( MY_INFINITE_GENERATOR ))
# ^ This is still an iterator. 
# If you want to materialize the items, e.g. in a list, do:
ltd_m = list( ltd )
# If you don't want the enumeration indices, you can strip them as usual:
ltd_no_enum = [ v for i,v in ltd_m ]

EDIT: Actually, islice is a much better option.编辑:实际上, islice是一个更好的选择。

limit = 10
limited_artists = [artist in xml.findall('artist')][:limit]
results = [xml_to_dict(artist) for limited_artists]

This avoids the issues of slicing: it doesn't change the order of operations, and doesn't construct a new list, which can matter for large lists if you're filtering the list comprehension.这避免了切片的问题:它不会改变操作顺序,也不会构造新列表,如果您正在过滤列表理解,这对于大型列表可能很重要。

def first(it, count):
    it = iter(it)
    for i in xrange(0, count):
        yield next(it)
    raise StopIteration

print [i for i in first(range(1000), 5)]

It also works properly with generator expressions, where slicing will fall over due to memory use:它也适用于生成器表达式,其中切片将因内存使用而失败:

exp = (i for i in first(xrange(1000000000), 10000000))
for i in exp:
    print i

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

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