बुलियन की सूची के आधार पर एक सूची को छानना


127

मेरे पास मूल्यों की एक सूची है जिसे मुझे मल की सूची में दिए गए मानों को फ़िल्टर करने की आवश्यकता है:

list_a = [1, 2, 4, 6]
filter = [True, False, True, False]

मैं निम्नलिखित पंक्ति के साथ एक नई फ़िल्टर की गई सूची बनाता हूं:

filtered_list = [i for indx,i in enumerate(list_a) if filter[indx] == True]

जिसके परिणामस्वरूप:

print filtered_list
[1,4]

लाइन काम करती है, लेकिन थोड़ा ओवरकिल दिखता है और मैं सोच रहा था कि क्या इसे हासिल करने का कोई सरल तरीका है।


सलाह

नीचे दिए गए उत्तरों में दी गई दो अच्छी सलाह का सारांश:

1- एक सूची का नाम नहीं है filterजैसे मैंने किया क्योंकि यह एक अंतर्निहित कार्य है।

2- चीजों की तुलना ऐसे न करें Trueजैसे मैंने किया है if filter[idx]==True..क्योंकि यह अनावश्यक है। बस इस्तेमाल if filter[idx]करना काफी है।


3
सिर्फ FYI करें, यह एक सामान्य समानांतर कंप्यूटिंग आदिम है जिसे स्ट्रीम कंपटीशन कहा जाता है(यह एक 'आदिम' क्योंकि यह आसान है कहा जाता है, लेकिन क्योंकि यह कई अन्य समानांतर एल्गोरिदम के लिए एक इमारत ब्लॉक के रूप में प्रयोग किया जाता है)
BlueRaja - डैनी Pflughoeft

2
कुछ शैली नोट: if filter[indx] == Trueकरो नहीं का उपयोग ==आप के साथ पहचान के लिए जाँच करना चाहते हैं True, का उपयोग करें is। वैसे भी इस मामले में पूरी तुलना बेकार है, आप बस इस्तेमाल कर सकते हैं if filter[indx]। अन्त में: एक चर / मॉड्यूल नाम के रूप में अंतर्निहित नाम का उपयोग कभी नहीं करें (मैं नाम का उल्लेख कर रहा हूं filter)। कुछ का उपयोग करना included, ताकि ifअच्छी तरह से पढ़ता है ( if included[indx])।
बकुरीउ

जवाबों:


184

आप देख रहे हैं itertools.compress:

>>> from itertools import compress
>>> list_a = [1, 2, 4, 6]
>>> fil = [True, False, True, False]
>>> list(compress(list_a, fil))
[1, 4]

समय की तुलना (py3.x):

>>> list_a = [1, 2, 4, 6]
>>> fil = [True, False, True, False]
>>> %timeit list(compress(list_a, fil))
100000 loops, best of 3: 2.58 us per loop
>>> %timeit [i for (i, v) in zip(list_a, fil) if v]  #winner
100000 loops, best of 3: 1.98 us per loop

>>> list_a = [1, 2, 4, 6]*100
>>> fil = [True, False, True, False]*100
>>> %timeit list(compress(list_a, fil))              #winner
10000 loops, best of 3: 24.3 us per loop
>>> %timeit [i for (i, v) in zip(list_a, fil) if v]
10000 loops, best of 3: 82 us per loop

>>> list_a = [1, 2, 4, 6]*10000
>>> fil = [True, False, True, False]*10000
>>> %timeit list(compress(list_a, fil))              #winner
1000 loops, best of 3: 1.66 ms per loop
>>> %timeit [i for (i, v) in zip(list_a, fil) if v] 
100 loops, best of 3: 7.65 ms per loop

filterएक चर नाम के रूप में उपयोग न करें , यह एक अंतर्निहित फ़ंक्शन है।


@ मीहदी मुझे मतलूब रास्ता बहुत अचूक लगता है, लेकिन मुझे लगता है कि यह इस बात पर निर्भर करता है कि आप किस चीज़ के अभ्यस्त हैं।
इयान गोल्डबी

मैं कैसे चयन कर सकता हूं [2, 6]?
फ्लोरेंट

मुझे मिल गया है, list(compress(list_a, [not i for i in fill]))लौटना चाहिए[2, 6]
फ्लोरेंट

42

इस तरह:

filtered_list = [i for (i, v) in zip(list_a, filter) if v]

का उपयोग कर रहा zipहैकिसी भी अनुक्रमण की आवश्यकता के बिना समानांतर में कई अनुक्रमों पर पुनरावृति करने के लिए पायथोनिक तरीका । यह मानता है कि दोनों अनुक्रमों की लंबाई समान है (सबसे छोटा रन आउट होने के बाद ज़िप बंद हो जाता है)। itertoolsइस तरह के एक साधारण मामले के लिए उपयोग करना थोड़ा मुश्किल है ...

एक बात जो आप अपने उदाहरण में करते हैं, आपको वास्तव में करना बंद कर देना चाहिए, यह सच की तुलना कर रहा है, यह आमतौर पर आवश्यक नहीं है। इसके बजाय if filter[idx]==True: ..., आप बस लिख सकते हैं if filter[idx]: ...


40

सुन्न के साथ:

In [128]: list_a = np.array([1, 2, 4, 6])
In [129]: filter = np.array([True, False, True, False])
In [130]: list_a[filter]

Out[130]: array([1, 4])

या देखें कि यदि सूची_ एक फ़िल्टर नहीं बल्कि एक सुव्यवस्थित सरणी हो सकती है तो एलेक्स स्ज़मैरी का उत्तर देखें

Numpy आमतौर पर आपको एक बड़ी गति को बढ़ावा देता है

In [133]: list_a = [1, 2, 4, 6]*10000
In [134]: fil = [True, False, True, False]*10000
In [135]: list_a_np = np.array(list_a)
In [136]: fil_np = np.array(fil)

In [139]: %timeit list(itertools.compress(list_a, fil))
1000 loops, best of 3: 625 us per loop

In [140]: %timeit list_a_np[fil_np]
10000 loops, best of 3: 173 us per loop

अच्छा बिंदु, मैं उपयोग करने को प्राथमिकता NumPyसे अधिक listजहां संभव हो। लेकिन अगर आपको किसी listभी तरह से उपयोग करने की आवश्यकता है , तो आपके पास ( NumPyसमाधान का उपयोग करके ) np.arrayदोनों सूचियों से बना है, बूलियन अनुक्रमण का उपयोग करें और अंत में tolist()विधि के साथ सूची में सरणी परिवर्तित करना । सटीक होने के लिए, आपको उन वस्तुओं को समय की तुलना में शामिल करना चाहिए। फिर, उपयोग itertools.compressकरना अभी भी सबसे तेज़ समाधान होगा।
नेरक्सिस

17

इस numpy का उपयोग कर, ऐसा करने के लिए यानी, आप एक सरणी है, aके बजाय list_a:

a = np.array([1, 2, 4, 6])
my_filter = np.array([True, False, True, False], dtype=bool)
a[my_filter]
> array([1, 4])

3
यदि आप my_filter को बूलियन एरे में बदलते हैं, तो आप बिना आवश्यकता के, सीधे बूलियन इंडेक्सिंग का उपयोग कर सकते हैं where
बास स्विंकल्स


-1

अजगर 3 के साथ आप मूल्यों list_a[filter]को प्राप्त करने के लिए उपयोग कर सकते हैं TrueFalseमूल्यों का उपयोग करने के लिएlist_a[~filter]

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.