यदि किसी सूची के सभी तत्व किसी शर्त से मेल खाते हैं तो कैसे जांचें?


208

मेरे पास एक सूची है जिसमें 20000 सूची शामिल हैं। मैं ध्वज के रूप में प्रत्येक सूची के तीसरे तत्व का उपयोग करता हूं। मैं इस सूची में कुछ संचालन करना चाहता हूं जब तक कि कम से कम एक तत्व का झंडा 0 है, यह इस प्रकार है:

my_list = [["a", "b", 0], ["c", "d", 0], ["e", "f", 0], .....]

शुरुआत में, सभी झंडे 0 हैं। मैं थोड़ी देर के लूप का उपयोग करता हूं यह जांचने के लिए कि क्या कम से कम एक तत्व का झंडा 0 है:

def check(list_):
    for item in list_:
        if item[2] == 0:
            return True
    return False

यदि check(my_list)रिटर्न मिलता है True, तो मैं अपनी सूची पर काम करना जारी रखता हूं:

while check(my_list):
    for item in my_list:
        if condition:
            item[2] = 1
        else:
            do_sth()

दरअसल, मैं my_list में एक तत्व को हटाना चाहता था क्योंकि मैंने इस पर iterated किया था, लेकिन जैसे ही मैं इसके बारे में पुनरावृति करता हूं, मुझे आइटम निकालने की अनुमति नहीं है।

मूल my_list में झंडे नहीं थे:

my_list = [["a", "b"], ["c", "d"], ["e", "f"], .....]

चूँकि मैं तत्वों को हटा नहीं सका क्योंकि मैंने इस पर ध्यान दिया, मैंने इन झंडों का आविष्कार किया। लेकिन my_listकई आइटम शामिल हैं, और whileलूप उन सभी को प्रत्येक forलूप में पढ़ता है , और इसमें बहुत समय लगता है! क्या तुम्हारे पास कोई सुझाव है?


3
ऐसा लगता है कि आपकी डेटा संरचना आपकी समस्या के लिए आदर्श नहीं है। यदि आपने संदर्भ को थोड़ा और समझाया तो शायद हम कुछ और उपयुक्त सुझाव दे सकें।
uselpa

हो सकता है आप के साथ आइटम की जगह सकता है Noneया []आप उन्हें हटाने के बजाय सूची पर पुनरावृति के रूप में। 'लूप' (') के साथ पूरी सूची की जांच करना, आंतरिक लूप पर प्रत्येक पास से पहले सभी मदों पर पुनरावृत्ति करना एक बहुत ही धीमा तरीका है।
मार्टिउ

जवाबों:


402

यहां सबसे अच्छा जवाब उपयोग करना है all(), जो इस स्थिति के लिए बिलिन है। हम इसे जनरेटर अभिव्यक्ति के साथ जोड़ते हैं ताकि आप जिस परिणाम को साफ और कुशलता से प्राप्त कर सकें। उदाहरण के लिए:

>>> items = [[1, 2, 0], [1, 2, 0], [1, 2, 0]]
>>> all(flag == 0 for (_, _, flag) in items)
True
>>> items = [[1, 2, 0], [1, 2, 1], [1, 2, 0]]
>>> all(flag == 0 for (_, _, flag) in items)
False

ध्यान दें कि all(flag == 0 for (_, _, flag) in items)सीधे इसके बराबर है all(item[2] == 0 for item in items), इस मामले में पढ़ने के लिए बस थोड़ा सा अच्छा है।

और, फ़िल्टर उदाहरण के लिए, एक सूची समझ (निश्चित रूप से, आप एक जनरेटर अभिव्यक्ति का उपयोग कर सकते हैं जहाँ उपयुक्त हो):

>>> [x for x in items if x[2] == 0]
[[1, 2, 0], [1, 2, 0]]

यदि आप कम से कम एक तत्व की जाँच करना चाहते हैं, तो बेहतर विकल्प यह है any()कि अधिक पठनीय का उपयोग किया जाए:

>>> any(flag == 0 for (_, _, flag) in items)
True

लैम्ब्डा के उपयोग पर मेरी गलती, पायथन के सभी एक समारोह को हास्केल एट जैसे पहले तर्क के रूप में स्वीकार नहीं करते हैं। अल।, मैंने अपना उत्तर एक सूची समझ के रूप में भी बदल दिया। :)
हैम्पस निल्सन

3
@HampusNilsson एक सूची की समझ जनरेटर की अभिव्यक्ति के समान नहीं है। जैसे all()और any()शॉर्ट सर्किट, यदि, उदाहरण के लिए, मेरा पहला मान जिस पर मूल्यांकन करता है False, all()वह विफल हो जाएगा और किसी भी अधिक मान की जांच नहीं करेगा, वापस लौट जाएगा False। आपका उदाहरण भी यही करेगा, सिवाय इसके कि तुलना की पूरी सूची पहले ही बन जाएगी, जिसका अर्थ है बिना कुछ लिए बहुत सारी प्रोसेसिंग।
गारेथ लेटी

14

यदि आप यह जाँचना चाहते हैं कि सूची में कोई भी वस्तु किसी शर्त का उपयोग करती है या नहीं all:

if all([x[2] == 0 for x in lista]):
    # Will run if all elements in the list has x[2] = 0 (use not to invert if necessary)

मिलान नहीं करने वाले सभी तत्वों को निकालने के लिए, उपयोग करें filter

# Will remove all elements where x[2] is 0
listb = filter(lambda x: x[2] != 0, listb)

2
आप निकाल सकते हैं [...]में all(...), क्योंकि यह तो एक सूची है, जो न केवल आप दो पात्रों की बचत होती है के बजाय एक जनरेटर बना सकते हैं, लेकिन यह भी स्मृति और समय बचाता है। जनरेटर का उपयोग करके, एक समय में केवल एक आइटम की गणना की जाएगी (पूर्व परिणाम अब उपयोग नहीं किए जाने के बाद से गिरा दिया जाएगा) और यदि उनमें से कोई भी निकला False, तो जनरेटर बाकी की गणना करना बंद कर देगा।
क्यू

7

आप itertools की takewhile का उपयोग इस तरह से कर सकते हैं, यह एक बार एक शर्त पूरी होने के बाद बंद हो जाएगी जो आपके कथन को विफल करती है। विपरीत विधि ड्रॉपडाउन होगी

for x in itertools.takewhile(lambda x: x[2] == 0, list)
    print x

0

उपयोग करने का दूसरा तरीका itertools.ifilter। यह सत्यता और प्रक्रिया की जाँच करता है (उपयोग करते हुए lambda)

Sample-

for x in itertools.ifilter(lambda x: x[2] == 0, my_list):
    print x

0

यह तरीका उपयोग करने की तुलना में थोड़ा अधिक लचीला है all():

my_list = [[1, 2, 0], [1, 2, 0], [1, 2, 0]]
all_zeros = False if False in [x[2] == 0 for x in my_list] else True
any_zeros = True if True in [x[2] == 0 for x in my_list] else False

या अधिक सफलतापूर्वक:

all_zeros = not False in [x[2] == 0 for x in my_list]
any_zeros = 0 in [x[2] for x in my_list]

आप बस के लिए all_zeros = False in [x[2] == 0 for x in my_list]या यहां तक कि नहीं कह सकते हैं 0 in [x[2] for x in my_list]और इसी के लिए any_zeros? मैं वास्तव में कोई उल्लेखनीय सुधार नहीं देखता हूं all()
ट्रिपल जूल

नहीं, आपका संस्करण - मेरा मूल्यांकन all_zeros = False in [x[2] == 0 for x in my_list]करता है False, जबकि मेरा मूल्यांकन करता है True। यदि आप इसे बदलते हैं all_zeros = not (False in [x[2] == 0 for x in my_list])तो यह मेरे लिए बराबर है। और 0 in [x[2] for x in my_list]जाहिर है कि केवल काम करने जा रहा है any_zeros। लेकिन मुझे आपके विचार की
सफलता
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.