एक तानाशाह से खाली तार के साथ चाबी निकालने का कुशल तरीका


116

मेरे पास एक तानाशाही है और मैं उन सभी चाबियों को दूर करना चाहूंगा जिनके लिए खाली मूल्य के तार हैं।

metadata = {u'Composite:PreviewImage': u'(Binary data 101973 bytes)',
            u'EXIF:CFAPattern2': u''}

इसे करने का बेहतरीन तरीका क्या है?

जवाबों:


194

अजगर 2.X

dict((k, v) for k, v in metadata.iteritems() if v)

पायथन 2.7 - 3.X

{k: v for k, v in metadata.items() if v is not None}

ध्यान दें कि आपकी सभी कुंजियों में मान हैं। यह सिर्फ इतना है कि उन मूल्यों में से कुछ खाली स्ट्रिंग हैं। मूल्य के बिना एक तानाशाह में एक कुंजी के रूप में ऐसी कोई चीज नहीं है; यदि इसका कोई मूल्य नहीं है, तो यह तानाशाही में नहीं होगा।


29
+1। यह ध्यान रखना महत्वपूर्ण है कि यह वास्तव में मौजूदा शब्दकोश से कुंजियों को नहीं हटाता है। बल्कि, यह एक नया शब्दकोश बनाता है। आमतौर पर यह वही होता है जो कोई चाहता है और शायद वही होता है जिसे ओपी की जरूरत होती है, लेकिन यह वह नहीं है जो ओपी ने मांगा था।
स्टीवन रंबलस्की

18
यह भी v = 0 को मारता है, जो ठीक है, अगर वह चाहता है।
पॉल

2
यह भी rids वी झूठी =, जो है नहीं वास्तव में क्या ओ पी पूछा।
अमीर

4
@shredding: आपका मतलब है .items()
BrenBarn

6
अजगर के बाद के संस्करणों के लिए आपको डिक्शनरी जनरेटर का उपयोग भी करना चाहिए:{k: v for k, v in metadata.items() if v is not None}
शियाविनी

75

यह BrenBarn के समाधान से भी छोटा हो सकता है (और अधिक पठनीय मुझे लगता है)

{k: v for k, v in metadata.items() if v}

पायथन 2.7.3 के साथ परीक्षण किया गया।


13
यह शून्य मान को भी मारता है।
पॉल

10
0 (शून्य) को संरक्षित करने के लिए आप इसका उपयोग कर सकते हैं ... if v!=None: {k: v for k, v in metadata.items() if v!=None}
Dannid

1
{k: v for k, v के लिए मेटाडेटा.इटीम्स () में यदि v! = कोई नहीं} खाली तारों से छुटकारा नहीं मिलता है।
२१:२० पर फिल्गो २०

1
शब्दकोश समझ केवल पायथन 2.7+ के साथ समर्थित है पूर्व संस्करणों के साथ संगतता के लिए @ ब्रेनबर्न समाधान का उपयोग करें।
पवन गुप्ता

12
हमेशा '! =' के बजाय किसी के साथ ',' नहीं 'की तुलना करनी चाहिए। stackoverflow.com/a/14247419/2368836
rocktheartsm4l

21

यदि आपको वास्तव में मूल शब्दकोश को संशोधित करने की आवश्यकता है:

empty_keys = [k for k,v in metadata.iteritems() if not v]
for k in empty_keys:
    del metadata[k]

ध्यान दें कि हमें खाली कुंजियों की एक सूची बनानी होगी क्योंकि हम इसके माध्यम से पुनरावृति करते समय एक शब्दकोश को संशोधित नहीं कर सकते हैं (जैसा कि आपने देखा होगा)। यह एक नया शब्दकोश बनाने की तुलना में कम महंगा (मेमोरी-वार) है, हालांकि, जब तक कि खाली मानों के साथ बहुत सारी प्रविष्टियां नहीं होती हैं।


यह मान 0 को भी हटा देगा और 0 खाली नहीं है
JVK

2
आप अजगर 3+ उपयोग कर रहे हैं आप को बदलने के लिए .iteritems()के साथ .items(), पहले नवीनतम अजगर संस्करणों में अब और काम नहीं करता।
मारियानो रुइज़


12

यदि आप वास्तविक दुनिया डेटा संरचनाओं को संभालने के लिए एक पूर्ण-विशेषताओं, फिर भी रसीला दृष्टिकोण चाहते हैं जो अक्सर नेस्टेड होते हैं, और यहां तक ​​कि चक्र भी हो सकते हैं, तो मैं बोल्ट उपयोगिता उपयोगिता पैकेज से रीमैप उपयोगिता को देखने की सलाह देता हूं

अपने प्रोजेक्ट में iterutils.py को pip install boltonsकॉपी या कॉपी करने के बाद , बस करें:

from boltons.iterutils import remap

drop_falsey = lambda path, key, value: bool(value)
clean = remap(metadata, visit=drop_falsey)

इस पृष्ठ के कई और उदाहरण हैं, जिनमें जीथब के एपीआई से बहुत बड़ी वस्तुओं के साथ काम करना शामिल है।

यह शुद्ध-पायथन है, इसलिए यह हर जगह काम करता है, और पायथन 2.7 और 3.3+ में पूरी तरह से परीक्षण किया गया है। सबसे अच्छी बात, मैंने इसे इस तरह के मामलों के लिए लिखा है, इसलिए यदि आपको ऐसा मामला लगता है जो इसे नहीं संभालता है, तो आप मुझे इसे ठीक करने के लिए बग कर सकते हैं


1
इस समाधान ने मेरे पास एक समान समस्या के लिए बहुत अच्छा काम किया: शब्दकोशों के अंदर गहरी नेस्टेड सूचियों से खाली मानों को अलग करना। धन्यवाद!
निकोलस तुलच

1
यह अच्छा है, क्योंकि आप पहिया को सुदृढ़ नहीं कर रहे हैं, और नेस्टेड वस्तुओं के लिए एक समाधान प्रदान कर रहे हैं। धन्यवाद!
vekerdyb

1
मुझे वास्तव में आपके पुस्तकालय के लिए लिखा गया लेख पसंद आया, और यह एक उपयोगी पुस्तकालय है!
जीवनरक्षक

11

रयान के समाधान के आधार पर , यदि आपके पास सूची और नेस्टेड शब्दकोश भी हैं:

पायथन 2 के लिए:

def remove_empty_from_dict(d):
    if type(d) is dict:
        return dict((k, remove_empty_from_dict(v)) for k, v in d.iteritems() if v and remove_empty_from_dict(v))
    elif type(d) is list:
        return [remove_empty_from_dict(v) for v in d if v and remove_empty_from_dict(v)]
    else:
        return d

पायथन 3 के लिए:

def remove_empty_from_dict(d):
    if type(d) is dict:
        return dict((k, remove_empty_from_dict(v)) for k, v in d.items() if v and remove_empty_from_dict(v))
    elif type(d) is list:
        return [remove_empty_from_dict(v) for v in d if v and remove_empty_from_dict(v)]
    else:
        return d

1
हा, अच्छा विस्तार! निम्नलिखित जैसे शब्दकोशों के लिए यह एक अच्छा समाधान है:d = { "things": [{ "name": "" }] }
रायन शिया

6

यदि आपके पास एक नेस्टेड शब्दकोश है, और आप चाहते हैं कि यह खाली उप-तत्वों के लिए भी काम करे, तो आप ब्रेनबर्न के सुझाव के पुनरावर्ती संस्करण का उपयोग कर सकते हैं:

def scrub_dict(d):
    if type(d) is dict:
        return dict((k, scrub_dict(v)) for k, v in d.iteritems() if v and scrub_dict(v))
    else:
        return d

items()इसके बजाय iteritems()पायथन 3 के लिए उपयोग करें
बजे

6

त्वरित उत्तर (TL; DR)

Example01

### example01 -------------------

mydict  =   { "alpha":0,
              "bravo":"0",
              "charlie":"three",
              "delta":[],
              "echo":False,
              "foxy":"False",
              "golf":"",
              "hotel":"   ",                        
            }
newdict =   dict([(vkey, vdata) for vkey, vdata in mydict.iteritems() if(vdata) ])
print newdict

### result01 -------------------
result01 ='''
{'foxy': 'False', 'charlie': 'three', 'bravo': '0'}
'''

विस्तृत जवाब

संकट

  • संदर्भ: पायथन 2.x
  • परिदृश्य: डेवलपर की इच्छा रिक्त मूल्यों को बाहर करने के लिए एक शब्दकोश को संशोधित करती है
    • उर्फ एक शब्दकोश से खाली मूल्यों को हटा दें
    • उर्फ मान को रिक्त मान के साथ हटाएं
    • प्रत्येक कुंजी-मूल्य जोड़ी पर गैर-रिक्त मानों के लिए उर्फ ​​फ़िल्टर शब्दकोश

उपाय

  • example01 "खाली" मानों को हटाने के लिए सरल सशर्त के साथ अजगर सूची-बोध वाक्यविन्यास का उपयोग करें

नुकसान

  • example01 केवल मूल शब्दकोश की एक प्रति पर काम करता है (जगह में संशोधित नहीं होता है)
  • example01 अप्रत्याशित परिणाम उत्पन्न कर सकता है जो डेवलपर द्वारा "खाली" के आधार पर किया जाता है
    • क्या डेवलपर का मतलब उन मूल्यों को रखने से है जो झूठे हैं ?
    • यदि डिक्शनरी में मान स्ट्रिंग्स होने के लिए नहीं है, तो डेवलपर को अप्रत्याशित डेटा हानि हो सकती है।
    • result01 से पता चलता है कि मूल सेट से केवल तीन कुंजी-मूल्य जोड़े संरक्षित थे

वैकल्पिक उदाहरण

  • example02 संभावित नुकसान से निपटने में मदद करता है
  • सशर्त को बदलकर "रिक्त" की अधिक सटीक परिभाषा का उपयोग करने के लिए दृष्टिकोण है।
  • यहां हम केवल उन मानों को फ़िल्टर करना चाहते हैं जो रिक्त स्ट्रिंग्स का मूल्यांकन करते हैं।
  • यहाँ हम .strip () का उपयोग उन मूल्यों को फ़िल्टर करने के लिए करते हैं जिनमें केवल व्हाट्सएप शामिल है।

Example02

### example02 -------------------

mydict  =   { "alpha":0,
              "bravo":"0",
              "charlie":"three",
              "delta":[],
              "echo":False,
              "foxy":"False",
              "golf":"",
              "hotel":"   ",
            }
newdict =   dict([(vkey, vdata) for vkey, vdata in mydict.iteritems() if(str(vdata).strip()) ])
print newdict

### result02 -------------------
result02 ='''
{'alpha': 0,
  'bravo': '0', 
  'charlie': 'three', 
  'delta': [],
  'echo': False,
  'foxy': 'False'
  }
'''

यह सभी देखें



4

Patriciasz और nneonneo से उत्तर पर निर्माण , और इस संभावना के लिए लेखांकन कि आप उन कुंजियों को हटाना चाहते हैं जिनमें केवल कुछ मिथ्या बातें हैं (उदाहरण के लिए '') लेकिन अन्य नहीं (उदाहरण के लिए 0), या शायद आप भी कुछ सत्य चीजें (जैसे 'SPAM') शामिल करना चाहते हैं तो आप एक अत्यधिक विशिष्ट हिटलिस्ट बना सकते हैं:

unwanted = ['', u'', None, False, [], 'SPAM']

दुर्भाग्य से, यह काफी काम नहीं करता है, क्योंकि उदाहरण के लिए 0 in unwantedमूल्यांकन करता है True। हमें 0अन्य झूठी चीजों के बीच भेदभाव करने की आवश्यकता है , इसलिए हमें इसका उपयोग करना होगा is:

any([0 is i for i in unwanted])

... का मूल्यांकन करता है False

अब इसका उपयोग delअवांछित चीजों के लिए करें:

unwanted_keys = [k for k, v in metadata.items() if any([v is i for i in unwanted])]
for k in unwanted_keys: del metadata[k]

यदि आप जगह में संशोधन करने के बजाय एक नया शब्दकोश चाहते हैं metadata:

newdict = {k: v for k, v in metadata.items() if not any([v is i for i in unwanted])}

वास्तव में अच्छा शॉट, यह एक ही बार में कई समस्याओं को संबोधित करता है और यह सवाल हल करता है, इसे स्पष्ट करने के लिए धन्यवाद
jlandercy

ठंडा! यह इस उदाहरण के लिए काम करता है। हालाँकि, यह तब काम नहीं करता है जब शब्दकोश में एक आइटम है[]
jsga 13

2

मैंने इस धागे में सभी उत्तर पढ़े और कुछ ने इस धागे को भी संदर्भित किया: पुनरावर्ती फ़ंक्शन के साथ नेस्टेड शब्दकोश में खाली dicts निकालें

मैंने मूल रूप से यहां समाधान का इस्तेमाल किया और इसने बहुत अच्छा काम किया:

प्रयास 1: टू हॉट (प्रदर्शन या भविष्य के सबूत नहीं) :

def scrub_dict(d):
    if type(d) is dict:
        return dict((k, scrub_dict(v)) for k, v in d.iteritems() if v and scrub_dict(v))
    else:
        return d

लेकिन पायथन 2.7 दुनिया में कुछ प्रदर्शन और संगतता चिंताओं को उठाया गया था:

  1. के isinstanceबजाय का उपयोग करेंtype
  2. forदक्षता के लिए लूप में सूची COMP को अनियंत्रित करें
  3. के itemsबजाय सुरक्षित python3 का उपयोग करेंiteritems

प्रयास 2: बहुत ठंडा (यादों की कमी) :

def scrub_dict(d):
    new_dict = {}
    for k, v in d.items():
        if isinstance(v,dict):
            v = scrub_dict(v)
        if not v in (u'', None, {}):
            new_dict[k] = v
    return new_dict

DOH! यह पुनरावर्ती नहीं है और संस्मरणात्मक नहीं है।

प्रयास 3: बस सही (अब तक) :

def scrub_dict(d):
    new_dict = {}
    for k, v in d.items():
        if isinstance(v,dict):
            v = scrub_dict(v)
        if not v in (u'', None, {}):
            new_dict[k] = v
    return new_dict

1
जब तक मैं अंधा नहीं होता, तब तक मुझे लगता है कि प्रयास 2 और 3 बिल्कुल समान हैं ...
luckyguy73

1

एरेट्स के साथ मिश्रित डाई

  • प्रयास 3 का उत्तर : ब्लिसरेज के उत्तर से सिर्फ राइट (अभी तक) एरेस तत्वों को ठीक से संभाल नहीं पाता है। मैं पैच में शामिल हूँ अगर किसी को इसकी आवश्यकता हो। विधि हैंडल स्टेटमेंट ब्लॉक है if isinstance(v, list):, जो मूल scrub_dict(d)कार्यान्वयन का उपयोग करके सूची को स्क्रब करता है।
    @staticmethod
    def scrub_dict(d):
        new_dict = {}
        for k, v in d.items():
            if isinstance(v, dict):
                v = scrub_dict(v)
            if isinstance(v, list):
                v = scrub_list(v)
            if not v in (u'', None, {}):
                new_dict[k] = v
        return new_dict

    @staticmethod
    def scrub_list(d):
        scrubbed_list = []
        for i in d:
            if isinstance(i, dict):
                i = scrub_dict(i)
            scrubbed_list.append(i)
        return scrubbed_list

बहुत बढ़िया । । । मैंने कोड बेस में यह बदलाव किया था लेकिन आपकी टिप्पणी _ / _
BlissRage

0

एक वैकल्पिक तरीका है कि आप ऐसा कर सकते हैं, शब्दकोश समझ का उपयोग कर रहे हैं। इसके साथ संगत होना चाहिए2.7+

result = {
    key: value for key, value in
    {"foo": "bar", "lorem": None}.items()
    if value
}

0

यदि आप उपयोग कर रहे हैं तो यहां एक विकल्प है pandas:

import pandas as pd

d = dict.fromkeys(['a', 'b', 'c', 'd'])
d['b'] = 'not null'
d['c'] = ''  # empty string

print(d)

# convert `dict` to `Series` and replace any blank strings with `None`;
# use the `.dropna()` method and
# then convert back to a `dict`
d_ = pd.Series(d).replace('', None).dropna().to_dict()

print(d_)

0

ऊपर उल्लिखित कुछ विधियाँ उपेक्षा करती हैं यदि कोई पूर्णांक हैं और मान 0 और 0.0 के साथ तैरते हैं

यदि कोई उपरोक्त से बचना चाहता है तो नीचे दिए गए कोड का उपयोग कर सकता है (खाली स्ट्रिंग निकालता है और नेस्टेड डिक्शनरी और नेस्टेड सूची से कोई भी मूल्य नहीं):

def remove_empty_from_dict(d):
    if type(d) is dict:
        _temp = {}
        for k,v in d.items():
            if v == None or v == "":
                pass
            elif type(v) is int or type(v) is float:
                _temp[k] = remove_empty_from_dict(v)
            elif (v or remove_empty_from_dict(v)):
                _temp[k] = remove_empty_from_dict(v)
        return _temp
    elif type(d) is list:
        return [remove_empty_from_dict(v) for v in d if( (str(v).strip() or str(remove_empty_from_dict(v)).strip()) and (v != None or remove_empty_from_dict(v) != None))]
    else:
        return d

0

"जैसा कि मैं वर्तमान में पायथन के साथ अपने काम के लिए एक डेस्कटॉप एप्लिकेशन भी लिखता हूं, मैंने डेटा-एंट्री एप्लिकेशन में पाया जब बहुत सारी प्रविष्टि होती है और जो कुछ अनिवार्य नहीं हैं, इस प्रकार उपयोगकर्ता इसे खाली छोड़ सकता है, सत्यापन उद्देश्य के लिए, इसे हथियाना आसान है सभी प्रविष्टियाँ और फिर एक शब्दकोष की खाली कुंजी या मान को छोड़ दें। तो एक शो के ऊपर मेरा कोड, हम कैसे शब्दकोश को आसानी से निकाल सकते हैं, शब्दकोश की समझ का उपयोग करें और शब्दकोश मान तत्व रखें जो रिक्त नहीं है। मैं पायथन 3.8.3 का उपयोग करता हूं।

data = {'':'', '20':'', '50':'', '100':'1.1', '200':'1.2'}

dic = {key:value for key,value in data.items() if value != ''}

print(dic)

{'100': '1.1', '200': '1.2'}

कृपया पायथन संस्करण का उल्लेख करें यह भी नवीनतम संस्करण का समर्थन करेगा?
हसीबी मीर

वर्तमान में आपका उत्तर चिह्नित है क्योंकि निम्न गुणवत्ता को हटाया जा सकता है। कृपया सुनिश्चित करें कि आपके उत्तर में किसी भी कोड से अलग स्पष्टीकरण है।
टिम स्टैक

@TimStack कृपया LQ उत्तरों के लिए विलोपन की अनुशंसा करें।
10 प्रतिनिधि

@ 10 रिप मैं किसी ऐसे उत्तर के लिए विलोपन की सिफारिश नहीं करूंगा जो एक समाधान के रूप में काम कर सकता है, लेकिन किसी भी वर्णनात्मक टिप्पणी का अभाव है। मैं उपयोगकर्ता को सूचित करना और उन्हें सिखाना चाहूंगा कि बेहतर उत्तर कैसा दिखता है।
टिम स्टैक

@ हस्सेब मीर मैं नवीनतम पायथन 3.8.3 का उपयोग करता हूं
कोकोआफ्रैम

-2

कुछ बेंचमार्किंग:

1. सूची समझ फिर से तानाशाही

In [7]: %%timeit dic = {str(i):i for i in xrange(10)}; dic['10'] = None; dic['5'] = None
   ...: dic = {k: v for k, v in dic.items() if v is not None} 
   1000000 loops, best of 7: 375 ns per loop

2. सूची समझदार () का उपयोग कर फिर से बनाना

In [8]: %%timeit dic = {str(i):i for i in xrange(10)}; dic['10'] = None; dic['5'] = None
   ...: dic = dict((k, v) for k, v in dic.items() if v is not None)
1000000 loops, best of 7: 681 ns per loop

3. वी और कोई नहीं तो लूप और डिलीट कीज

In [10]: %%timeit dic = {str(i):i for i in xrange(10)}; dic['10'] = None; dic['5'] = None
    ...: for k, v in dic.items():
    ...:   if v is None:
    ...:     del dic[k]
    ...: 
10000000 loops, best of 7: 160 ns per loop

इसलिए लूप और डिलीट 160ns पर सबसे तेज है, सूची समझ आधी ~ 375ns पर धीमी है और एक कॉल के साथ है dict() आधा फिर से धीमा है ~ 680ns।

एक समारोह में 3 लपेटकर यह लगभग 275ns को फिर से वापस लाता है। मेरे लिए भी PyPy नीट अजगर से लगभग दोगुना तेज़ था।


लूप और डिलीट भी एक RunTimeError को फेंक सकते हैं, क्योंकि किसी दृश्य को पुनरावृत्त करते हुए किसी शब्दकोश को संशोधित करना मान्य नहीं है। docs.python.org/3/library/stdtypes.html s4.10.1
Airsource Ltd

आह यार अजगर 3 में ठीक है, लेकिन यह सच है कि अजगर 2.7 में नहीं है क्योंकि आइटम एक सूची देता है, इसलिए आपको list(dic.items())py में कॉल करना होगा 3. डिक्ट कॉम्प्रिहेंशन ftw तब? डेल अभी भी Null / खाली मानों के कम अनुपात के लिए तेज़ लगता है। मुझे लगता है कि उस सूची का निर्माण स्मृति के उपभोग के लिए सिर्फ उतना ही बुरा है जितना कि तानाशाही को फिर से बनाना।
रिचर्ड मैटी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.