2016-11-07 29 views
6

我有一些需要根據其中一個列表中的值進行過濾的並行列表。有時候我寫這樣的事情對其進行過濾:使用元組過濾和解包處理空案例

lista = [1, 2, 3] 
listb = [7, 8, 9] 
filtered_a, filtered_b = zip(*[(a, b) for (a, b) in zip(lista, listb) if a < 3]) 

這給filtered_a == (1, 2)filtered_b == (7, 8)

但是,改變最終條件從a < 3a < 0導致異常待提高:

Traceback (most recent call last): 
    ... 
ValueError: need more than 0 values to unpack 

我知道爲什麼會發生這種情況:列表理解是空的,所以它就像調用zip(*[]),這就像zip()一樣,它只是返回ns是一個空列表,無法將其解壓到單獨的filtered_a和filtered_b迭代中。

是否有更好的(更短,更簡單,更pythonic)過濾函數來處理空的情況?在空的情況下,我希望filtered_a和filtered_b是空的迭代器,所以下面的代碼可以保持不變。

+1

在這種情況下,你期望'filtered_a'和'filtered_b'是什麼? 'None'?空元組/列表? –

+0

@TomDalton - 忘記了,謝謝。現在添加到問題中:「在空白的情況下,我希望filtered_a和filtered_b是空的迭代器,所以下面的代碼可以保持不變。」 – Justin

回答

4

你可以簡單地短路使用默認值:

filtered_a, filtered_b = zip(*[(a, b) for a, b in zip(lista, listb) if a < 0]) or ([], []) 
print(filtered_b, filtered_a) 
# [] [] 

對於Python 3,你需要調用list在由zip返回的迭代器上,因此第一個操作數可以被評估爲空列表(不是迭代器),否則即使迭代器可能爲空時也不會達到默認值,因爲bool(iter([]))True

1

我可能會做這樣的事情:

lista = [1, 2, 3] 
listb = [7, 8, 9] 

filtered_abs = ((a, b) for (a, b) in zip(lista, listb) if a < 3]) 

for a, b in filtered_abs: 
    do_thing(a, b)