स्ट्रिंग की सूची से खाली स्ट्रिंग्स निकालें


683

मैं अजगर में तार की सूची से सभी खाली तारों को निकालना चाहता हूं।

मेरा विचार इस तरह दिखता है:

while '' in str_list:
    str_list.remove('')

क्या ऐसा करने के लिए और अधिक पाइथोनिक तरीका है?


45
@ इवो, उन बयानों में से कोई भी सच नहीं है। आपको एक सूची को कभी भी संशोधित नहीं करना चाहिए कि for x in listयदि आप उपयोग कर रहे हैं तो आप while loopठीक हैं। प्रदर्शित लूप खाली तारों को हटा देगा, जब तक कि अधिक खाली तार न हों और फिर रुक जाएं। मैंने वास्तव में प्रश्न (सिर्फ शीर्षक) पर ध्यान नहीं दिया था, लेकिन मैंने सटीक लूप के साथ एक संभावना के रूप में उत्तर दिया था! यदि आप स्मृति के लिए समझ या फ़िल्टर का उपयोग नहीं करना चाहते हैं, तो यह एक बहुत ही पायथोनिक समाधान है।
अपरोनस्टरलिंग

4
फिर भी आप जिस सूची को देख रहे हैं, उस पर कभी भी बदलाव न करने का एक बहुत ही मान्य बिंदु :)
एडुआर्ड लुका

1
@EduardLuca यदि किसी सूची पर पुनरावृत्ति करने की बात यह है कि इसे बदलना है, तो आपको इसके विपरीत करना चाहिए। आपको बस इतना ध्यान रखना है कि आप जानते हैं कि ऐसा करने से आप अप्रत्याशित व्यवहार का कारण नहीं बनते हैं।
JFA

1
@EduardLuca, @JFA: मुद्दा यह है कि वह किसी सूची में नहीं है। यदि वह फॉर्म में कुछ लिखा होता तो वह for var in list:यहां लिखा होता while const in list:। जो किसी भी चीज़ पर ध्यान नहीं दे रहा है। यह केवल एक ही कोड दोहरा रहा है जब तक कि एक शर्त झूठी न हो।
कैमियन

जवाबों:


1153

मैं उपयोग करेगा filter:

str_list = filter(None, str_list)
str_list = filter(bool, str_list)
str_list = filter(len, str_list)
str_list = filter(lambda item: item, str_list)

अजगर 3 से एक पुनरावृत्ति देता है filter, इसलिए इसे कॉल में लपेटा जाना चाहिएlist()

str_list = list(filter(None, str_list))

11
यदि आप कि प्रदर्शन के लिए दबाया, itertoolकीifilter भी faster- है >>> timeit('filter(None, str_list)', 'str_list=["a"]*1000', number=100000) 2.3468542098999023; >>> timeit('itertools.ifilter(None, str_list)', 'str_list=["a"]*1000', number=100000) 0.04442191123962402
हम्फ्री बोगार्ट

4
@cpburnz बहुत सच है। हालांकि, ifilterपरिणामों के साथ आलसी का मूल्यांकन किया जाता है, एक बार में नहीं- मैं तर्क देता हूं कि ज्यादातर मामलों के ifilterलिए बेहतर है। दिलचस्प है कि उपयोग filterकरना अभी भी एक ifilterमें लपेटकर से तेज है list
हम्फ्री बोगार्ट

3
यदि आप संख्याओं की सूची में ऐसा करते हैं, तो ध्यान दें कि शून्य भी हटा दिए जाएंगे (ध्यान दें: मैंने केवल पहले 3 तरीकों का उपयोग किया था), इसलिए आपको वैकल्पिक विधि की आवश्यकता होगी।
SnoringFrog

2
यह केवल गति पर ध्यान केंद्रित करता है, न कि यह कि कैसे pythonic समाधान है (सवाल जो पूछा गया था)। सूची की समझ पाइथोनिक समाधान है, और फ़िल्टर का उपयोग केवल तभी किया जाना चाहिए जब प्रोफाइलिंग ने साबित कर दिया है कि सूची एक अड़चन है।
ट्रिटियम

3
@ जो भी उल्लेख-के बारे में-या-प्रति-पायथन -३, कृपया उत्तर को केवल संपादित करें और अपडेट करें। हम केवल अजगर 2 के लिए चर्चा कर रहे थे जब यह सवाल पूछा गया था, यहां तक ​​कि अजगर 3 को लगभग 2 साल जारी किया गया था। लेकिन पायथन 2 और 3 दोनों परिणामों को अपडेट करें।
लिविबेट्टर

236

सूची बोध का उपयोग करना सबसे पायथन तरीका है:

>>> strings = ["first", "", "second"]
>>> [x for x in strings if x]
['first', 'second']

यदि सूची को इन-प्लेस में संशोधित किया जाना चाहिए, क्योंकि अन्य संदर्भ हैं जो अद्यतन किए गए डेटा को देखना चाहिए, तो एक स्लाइस असाइनमेंट का उपयोग करें:

strings[:] = [x for x in strings if x]

16
मुझे यह समाधान पसंद है क्योंकि यह आसानी से अनुकूलनीय है। अगर मुझे न केवल खाली तारों को हटाने की आवश्यकता है, बल्कि तार जो कि सिर्फ व्हाट्सएप हैं, उदाहरण के लिए [x for x in strings if x.strip()]:।
बंधन

67

फ़िल्टर वास्तव में इसके लिए एक विशेष विकल्प है:

filter(None, sequence)

यह उन सभी तत्वों को फ़िल्टर कर देगा जो गलत मूल्यांकन करते हैं। यहां किसी वास्तविक कॉल करने योग्य का उपयोग करने की आवश्यकता नहीं है जैसे कि बूल, लेन और इतने पर।

यह मानचित्र के समान तेज़ है (बूल, ...)


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

24
>>> lstr = ['hello', '', ' ', 'world', ' ']
>>> lstr
['hello', '', ' ', 'world', ' ']

>>> ' '.join(lstr).split()
['hello', 'world']

>>> filter(None, lstr)
['hello', ' ', 'world', ' ']

समय की तुलना करें

>>> from timeit import timeit
>>> timeit('" ".join(lstr).split()', "lstr=['hello', '', ' ', 'world', ' ']", number=10000000)
4.226747989654541
>>> timeit('filter(None, lstr)', "lstr=['hello', '', ' ', 'world', ' ']", number=10000000)
3.0278358459472656

ध्यान दें कि filter(None, lstr)एक जगह के साथ खाली तारों को नहीं हटाता है ' ', यह केवल दूर करता है ''जबकि ' '.join(lstr).split()दोनों को हटा देता है।

filter()हटाए गए सफेद स्थान के तारों का उपयोग करने के लिए , इसमें बहुत अधिक समय लगता है:

>>> timeit('filter(None, [l.replace(" ", "") for l in lstr])', "lstr=['hello', '', ' ', 'world', ' ']", number=10000000)
18.101892948150635

यदि आपके पास किसी शब्द के स्ट्रिंग में स्थान है तो यह काम नहीं करेगा। उदाहरण के लिए: ['हैलो वर्ल्ड', '', 'हैलो', '']। >> ['हेलोवर्ल्ड', '', 'हैलो', ''] क्या आपके पास सूची में एक आइटम के भीतर रिक्त स्थान रखने के लिए कोई और उपाय है लेकिन दूसरों को हटा रहा है?
रेहान_मं

ध्यान दें कि filter(None, lstr)रिक्त स्थान को स्ट्रिंग के साथ नहीं हटाया जाता है' ' हाँ, क्योंकि वह खाली स्ट्रिंग नहीं है।
AMC

15

@ Ib33X से उत्तर भयानक है। यदि आप हर खाली स्ट्रिंग को निकालना चाहते हैं, तो छीनने के बाद। आपको स्ट्रिप विधि का भी उपयोग करने की आवश्यकता है। अन्यथा, यह खाली स्ट्रिंग वापस कर देगा भले ही उसके पास सफेद स्थान हो। जैसे, "" उस उत्तर के लिए भी मान्य होगा। तो, द्वारा प्राप्त किया जा सकता है।

strings = ["first", "", "second ", " "]
[x.strip() for x in strings if x.strip()]

इसके लिए जवाब होगा ["first", "second"]
यदि आप filterइसके बजाय विधि का उपयोग करना चाहते हैं , तो आप पसंद कर सकते हैं
list(filter(lambda item: item.strip(), strings))। यह वही परिणाम देता है।


12

यदि x के बजाय, मैं खाली स्ट्रिंग को समाप्त करने के लिए X! = '' का उपयोग करूंगा। ऐशे ही:

str_list = [x for x in str_list if x != '']

यह आपकी सूची में कोई भी डेटा प्रकार संरक्षित नहीं करेगा। साथ ही, यदि आपकी सूची में पूर्णांक हैं और 0 उनमें से एक है, तो इसे भी संरक्षित रखा जाएगा।

उदाहरण के लिए,

str_list = [None, '', 0, "Hi", '', "Hello"]
[x for x in str_list if x != '']
[None, 0, "Hi", "Hello"]

2
यदि आपकी सूचियों में भिन्न प्रकार हैं (कोई नहीं) को छोड़कर, तो आपको बड़ी समस्या हो सकती है।
ट्रिटियम

किस प्रकार? मैंने इंट और अन्य संख्यात्मक प्रकारों, स्ट्रिंग्स, सूचियों, ट्यूप्स, सेट्स और किसी के साथ और कोई समस्या नहीं होने की कोशिश की। मैं देख सकता था कि अगर कोई भी उपयोगकर्ता परिभाषित प्रकार है जो समर्थन नहीं करता है str विधि एक समस्या दे सकता है। क्या मुझे किसी अन्य के बारे में चिंतित होना चाहिए?
तेरुवेंकदम

1
यदि आपके पास ए है str_list = [None, '', 0, "Hi", '', "Hello"], तो यह एक खराब डिज़ाइन किए गए एप्लिकेशन का संकेत है। आपके पास एक से अधिक इंटरफ़ेस (प्रकार) और एक ही सूची में कोई भी नहीं होना चाहिए
ट्रिटियम

3
DB से डेटा पुनर्प्राप्त कर रहा है? स्वचालित परीक्षण करते समय एक समारोह के लिए तर्कों की सूची?
तेरुवेंकदम

3
वे आमतौर पर ट्यूपल हैं।
ट्रिटियम

7

आपकी सूची के आकार के आधार पर, यदि आप नई सूची बनाने के बजाय list.remove () का उपयोग करते हैं तो यह सबसे अधिक कारगर हो सकता है:

l = ["1", "", "3", ""]

while True:
  try:
    l.remove("")
  except ValueError:
    break

नई सूची न बनाने का यह फायदा है, लेकिन हर बार शुरुआत से ही खोज करने का नुकसान होता है, हालांकि while '' in lऊपर प्रस्तावित के रूप में उपयोग करने के विपरीत , इसमें केवल एक बार होने वाली खोज की आवश्यकता होती है ''(निश्चित रूप से सबसे अच्छा रखने का एक तरीका है दोनों विधियाँ, लेकिन यह अधिक जटिल है)।


1
आप सूची में जगह बनाकर संपादित कर सकते हैं ary[:] = [e for e in ary if e]। बहुत क्लीनर और नियंत्रण प्रवाह के लिए अपवाद का उपयोग नहीं करता है।
क्रिज़ीस्तोफ़ कार्स्की

2
ठीक है, यह वास्तव में "जगह में" नहीं है - मुझे पूरा यकीन है कि यह एक नई सूची बनाता है और बस इसे पुराने के नाम पर असाइन करता है।
एंड्रयू जफ

यह बहुत खराब तरीके से प्रदर्शन करता है क्योंकि डेटा की पूंछ प्रत्येक हटाने पर स्मृति में घुलमिल जाती है। एक हिट में सभी को हटाने के लिए बेहतर है।
विम

7

ध्यान रखें कि यदि आप एक स्ट्रिंग के भीतर सफेद रिक्त स्थान रखना चाहते हैं , तो आप कुछ तरीकों का उपयोग करके उन्हें अनजाने में हटा सकते हैं। यदि आपके पास यह सूची है

['हैलो दुनिया', '', '', 'हैलो'] आप क्या चाहते हो सकता है ['हैलो दुनिया', 'हैलो']

किसी भी प्रकार की सफेद जगह को रिक्त स्ट्रिंग में बदलने के लिए पहले सूची को ट्रिम करें:

space_to_empty = [x.strip() for x in _text_list]

फिर उन्हें सूची से खाली स्ट्रिंग हटा दें

space_clean_list = [x for x in space_to_empty if x]

यदि आप एक स्ट्रिंग के भीतर सफेद रिक्त स्थान रखना चाहते हैं, तो आप कुछ तरीकों का उपयोग करके उन्हें अनजाने में हटा सकते हैं। इस दृष्टिकोण की तरह, फिर?
AMC

धन्यवाद दोस्त, यह मेरे लिए थोड़ा बदलाव के साथ काम किया। अर्थातspace_clean_list = [x.strip() for x in y if x.strip()]
मुहम्मद मेहरान खान अटारी

6

उपयोग करें filter:

newlist=filter(lambda x: len(x)>0, oldlist) 

फ़िल्टर का उपयोग करने की कमियां बताई गई हैं कि यह विकल्पों की तुलना में धीमी है; भी, lambdaआमतौर पर महंगा है।

या आप सबसे सरल और सभी के सबसे पुनरावृत्तियों के लिए जा सकते हैं:

# I am assuming listtext is the original list containing (possibly) empty items
for item in listtext:
    if item:
        newlist.append(str(item))
# You can remove str() based on the content of your original list

यह तरीकों का सबसे सहज है और इसे सभ्य समय में करता है।


9
एसओ में आपका स्वागत है। आपको नजरअंदाज नहीं किया गया है। आप पर किसी भी तोपची द्वारा हमला नहीं किया गया है। आपको प्रतिक्रिया दी गई है। प्रवर्धन: फ़िल्टर के लिए आपका प्रस्तावित पहला अर्ग, उससे भी lambda x: len(x)बदतर है, lambda x : xजो चयनित उत्तर में 4 में से सबसे खराब है। सही कामकाज पसंद किया जाता है, लेकिन पर्याप्त नहीं है। अपने कर्सर को डाउनवोट बटन पर होवर करें: यह कहता है "यह उत्तर उपयोगी नहीं है"।
जॉन मैकिन

5

जैसा कि अज़ीज़ ऑल्टो द्वारा रिपोर्ट किया गया है कि filter(None, lstr)एक जगह के साथ खाली तारों को नहीं हटाया जाता है, ' 'लेकिन अगर आपको यकीन है कि लस्ट में केवल स्ट्रिंग है जिसका आप उपयोग कर सकते हैंfilter(str.strip, lstr)

>>> lstr = ['hello', '', ' ', 'world', ' ']
>>> lstr
['hello', '', ' ', 'world', ' ']
>>> ' '.join(lstr).split()
['hello', 'world']
>>> filter(str.strip, lstr)
['hello', 'world']

मेरे पीसी पर समय की तुलना करें

>>> from timeit import timeit
>>> timeit('" ".join(lstr).split()', "lstr=['hello', '', ' ', 'world', ' ']", number=10000000)
3.356455087661743
>>> timeit('filter(str.strip, lstr)', "lstr=['hello', '', ' ', 'world', ' ']", number=10000000)
5.276503801345825

''एक स्थान के साथ तारों को हटाने और खाली करने का सबसे तेज़ समाधान ' 'बना हुआ है ' '.join(lstr).split()

जैसा कि एक टिप्पणी में बताया गया है कि स्थिति अलग है अगर आपके तार में रिक्त स्थान हैं।

>>> lstr = ['hello', '', ' ', 'world', '    ', 'see you']
>>> lstr
['hello', '', ' ', 'world', '    ', 'see you']
>>> ' '.join(lstr).split()
['hello', 'world', 'see', 'you']
>>> filter(str.strip, lstr)
['hello', 'world', 'see you']

आप देख सकते हैं कि उस filter(str.strip, lstr)पर रिक्त स्थान के साथ तार संरक्षित है लेकिन ' '.join(lstr).split()इस तार को विभाजित करेगा।


1
यह केवल तभी काम करता है जब आपके तार में रिक्त स्थान न हों। अन्यथा, आप उन तारों को भी विभाजित कर रहे हैं।
phillyslick

1
@BenPolinsky जैसा कि आपने बताया कि joinसमाधान अंतरिक्ष के साथ तार को विभाजित करेगा लेकिन फ़िल्टर नहीं होगा। धन्यवाद, आपने टिप्पणी की तो मैंने अपने उत्तर में सुधार किया।
पाओलो मेल्चियोरे

-1

सबसे अच्छे उत्तर दें:

1. अलग करना छोड़ने के बिना खाली कर दें:

यही कारण है कि, सभी-स्पेस स्ट्रिंग्स को बरकरार रखा गया है:

slist = list(filter(None, slist))

सकारात्मक:

  • सबसे सरल;
  • सबसे तेज़ (नीचे दिए गए मानदंड देखें)।

2. अलग करने के बाद खाली करने के लिए ...

2.A ... जब तार में शब्दों के बीच रिक्त स्थान नहीं होते हैं:

slist = ' '.join(slist).split()

सकारात्मक:

  • छोटा कोड
  • तेजी से (लेकिन स्मृति के कारण बड़े डेटासेट के साथ सबसे तेज़ नहीं है, जो @ पाओलो-मेल्चीयर परिणाम के विपरीत है)

2. बी ... जब तारों में शब्दों के बीच रिक्त स्थान होता है?

slist = list(filter(str.strip, slist))

सकारात्मक:

  • सबसे तेजी से;
  • कोड की समझ।

2018 मशीन पर बेंचमार्क:

## Build test-data
#
import random, string
nwords = 10000
maxlen = 30
null_ratio = 0.1
rnd = random.Random(0)                  # deterministic results
words = [' ' * rnd.randint(0, maxlen)
         if rnd.random() > (1 - null_ratio)
         else
         ''.join(random.choices(string.ascii_letters, k=rnd.randint(0, maxlen)))
         for _i in range(nwords)
        ]

## Test functions
#
def nostrip_filter(slist):
    return list(filter(None, slist))

def nostrip_comprehension(slist):
    return [s for s in slist if s]

def strip_filter(slist):
    return list(filter(str.strip, slist))

def strip_filter_map(slist): 
    return list(filter(None, map(str.strip, slist))) 

def strip_filter_comprehension(slist):  # waste memory
    return list(filter(None, [s.strip() for s in slist]))

def strip_filter_generator(slist):
    return list(filter(None, (s.strip() for s in slist)))

def strip_join_split(slist):  # words without(!) spaces
    return ' '.join(slist).split()

## Benchmarks
#
%timeit nostrip_filter(words)
142 µs ± 16.8 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

%timeit nostrip_comprehension(words)
263 µs ± 19.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit strip_filter(words)
653 µs ± 37.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit strip_filter_map(words)
642 µs ± 36 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit strip_filter_comprehension(words)
693 µs ± 42.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit strip_filter_generator(words)
750 µs ± 28.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit strip_join_split(words)
796 µs ± 103 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

s and s.strip()बस के लिए सरलीकृत किया जा सकता है s.strip()
एएमसी

s and s.strip()जरूरत है अगर हम पूरी तरह से दोहराने के लिए filter(None, words), स्वीकृत जवाब चाहते हैं। मैंने ऊपर x2 नमूना फ़ंक्शंस ठीक किए और एक्स 2 बुरे लोगों को गिरा दिया।
एकॉस्टिस

-2

रिक्त स्थान और रिक्त मानों के संयोजन वाली सूची के लिए, सरल सूची समझ का उपयोग करें -

>>> s = ['I', 'am', 'a', '', 'great', ' ', '', '  ', 'person', '!!', 'Do', 'you', 'think', 'its', 'a', '', 'a', '', 'joke', '', ' ', '', '?', '', '', '', '?']

तो, आप देख सकते हैं, इस सूची में रिक्त स्थान और अशक्त तत्वों का एक संयोजन है। स्निपेट का उपयोग करना -

>>> d = [x for x in s if x.strip()]
>>> d
>>> d = ['I', 'am', 'a', 'great', 'person', '!!', 'Do', 'you', 'think', 'its', 'a', 'a', 'joke', '?', '?']
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.