简体   繁体   中英

Trying to conditionally append tuples from a list of tuples to sublists of tuples in a dictionary

I am at a loss on how to achieve what I want, so I'm posting here.

I have a dictionary where each value is a list of tuples (I'll call it dict1 ), which I am cross referencing against a list of tuples (I'll call it list1 ). The idea is to append any tuple that is in list1 to each sublist in dict1 if it doesn't already exist in the sublist in the form of (tuple, 0).

Here's what it looks like:

dict1 = {2011: [('Debt collection', 5572),
                ('Mortgage', 4483),
                ('Student loan', 431)],
         2012: [('Consumer Loan', 480),
                ('Student loan', 1632),
                ('Medical loan', 1632),
                ('Prepaid card', 83)]}

list1 = [('Debt collection', 5572),
         ('Mortgage', 4483),
         ('Credit reporting', 3230),
         ('Checking or savings account', 2068),
         ('Student loan', 1632),
         ('Credit card or prepaid card', 1577),
         ('Bank account or service', 1327),
         ('Credit card', 1156),
         ('Consumer Loan', 480)]

I want my code to check if the first part of each tuple in list1 exists in each value list of dict1, and if it doesn't, to append it to each value list in the form of (tuple, 0):

dict1 = {2011: [('Debt collection', 5572),
                ('Mortgage', 4483),
                ('Student loan', 431),
                ('Credit reporting', 0),
                ('Checking or savings account', 0),
                ('Credit card or prepaid card', 0),
                ('Bank account or service', 0),
                ('Credit card', 0),
                ('Consumer Loan', 0)],
         2012: [('Consumer Loan', 480),
                ('Student loan', 1632),
                ('Medical loan', 1632),
                ('Prepaid card', 83),
                ('Debt collection', 0),
                ('Mortgage', 0),
                ('Credit reporting', 0),
                ('Checking or savings account', 0),
                ('Credit card or prepaid card', 0),
                ('Bank account or service', 0),
                ('Credit card', 0)]}

I've tried first to extract the first part of each tuple in list1 as a separate list:

 available = [tpl[0] for tpl in list1]

Then I attempt the following:

 dict1.update(v.extend(tuple((tpl[0],0)) for tpl in v \ 
              for k, v in dict1.items() \
              if tpl[0] not in available))

I get the following error:

TypeError                                 Traceback (most recent call last)
<ipython-input-79-53b4b903b6f4> in <module>()
----> 1 dict1.update(v.extend(list(tuple((tpl[0],0)) for tpl in v for k, v in dict1.items()                      
if tpl[0] not in available)))

<ipython-input-79-53b4b903b6f4> in <genexpr>(.0)
----> 1 dict1.update(v.extend(list(tuple((tpl[0],0)) for tpl in v for k, v in dict1.items()                      
if tpl[0] not in available)))

TypeError: 'generator' object is not subscriptable

I was looking but didn't find anything that really went over a similar type of case. I'm assuming that I have to use .update for dict1 and also .extend on each list of values (v) in order to deal with each list individually.

For your problem, dictionaries are easier to handle than lists of tuples. In this case, you can combine mappings via a dictionary comprehension.

from operator import itemgetter

# create dictionary with all keys set to 0
allkeys = dict.fromkeys(map(itemgetter(0), list1), 0)

# for each year, combine dictionary mappings
dict1 = {k: {**allkeys, **dict(v)} for k, v in dict1.items()}

You can, if you wish, convert back to lists of tuples:

res = {k: list(v.items()) for k, v in dict1.items()}

Result for the nested dictionary option:

{2011: {'Debt collection': 5572,
  'Mortgage': 4483,
  'Credit reporting': 0,
  'Checking or savings account': 0,
  'Student loan': 431,
  'Credit card or prepaid card': 0,
  'Bank account or service': 0,
  'Credit card': 0,
  'Consumer Loan': 0},
 2012: {'Debt collection': 0,
  'Mortgage': 0,
  'Credit reporting': 0,
  'Checking or savings account': 0,
  'Student loan': 1632,
  'Credit card or prepaid card': 0,
  'Bank account or service': 0,
  'Credit card': 0,
  'Consumer Loan': 480,
  'Medical loan': 1632,
  'Prepaid card': 83}}

You can convert each value into a dict temporarily, use get to ensure a full complement of values, and write it back as a list. This requires no imports:

for k in dict1:
    d = dict(dict1[k])
    dict1[k] = [(item, d.get(item, 0)) for item, _ in list1]

If you want to have a dictionary in the output, the last line barely changes:

dict1[k] = {item: d.get(item, 0)) for item, _ in list1}

Or, if order matters and you are using Python < 3.6:

dict1 = OrderedDict(item, d.get(item, 0)) for item, _ in list1)

While I would encourage you not to, a one liner is possible:

dict1 = {k: [(item, d.get(item, 0)) for item, _ in list1] for k, d in ((k, dict(v)) for k, v in dict1.items())}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM