2010-08-20 63 views
3
的限制

基本上,我想這樣做(僞代碼,不是有效的Python):Python的成語:列表理解與項目

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

所以,我怎麼能在一個簡潔高效的方式編寫這個? XML文件可以包含0到50個藝術家之間的任何內容,並且我無法控制每次獲得的數量,AFAIK也沒有XPATH表達式來表示「讓我多達10個節點」。

謝謝!

回答

5

假設xmlElementTree對象,該findall()方法返回一個列表,所以只切該名單:

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

+1:快幾秒。 – 2010-08-20 21:30:57

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

+1同步! – jathanism 2010-08-20 20:36:18

2

這樣就避免了分片的問題:它不會改變的順序操作,並且不會構建新列表,如果您要過濾列表理解,這對於大型列表可能很重要。

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)] 

它還生成器表達式正常工作,在切片會翻倒,由於內存使用:

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

你並不需要**來提升'StopIteration'。簡單地結束功能就可以了。 – 2010-08-20 21:31:52

6

是否使用lxml?您可以使用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'] 

你也可以use itertools.islice to limit any iterable,例如

>>> 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'] 
+0

您認爲XPath解決方案比切片替代方案更快嗎?我認爲元素是懶惰的,但是如果不能很好地獲取元素,可能會更快一些?不確定 – adamJLev 2010-08-20 21:53:01

+0

@Infinity:我認爲'islice'更快,因爲XPath更復雜。雖然我沒有證實。你需要自己進行基準測試。 – kennytm 2010-08-21 05:58:33

2

對於其他人誰發現了這個問題,因爲他們試圖限制項目從無限發生器返回:

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 ]