简体   繁体   中英

Independent objects needed when zipping into dict

I have a list of items:

my_list = ['first', 'second', 'third']

I need to convert this items into a dictionary (so I can access each element by it's name), and associate multiple counters to each element: counter1, counter2, counter3.

So I do the following:

counter_dict = {'counter1': 0, 'counter2': 0, 'counter3': 0}

my_dict = dict(zip(mylist, [counter_dict]*len(mylist)))

This way I obtain a nested dictionary

{
  'first': {
    'counter1': 0,
    'counter2': 0,
    'counter3': 0
  },
  'second': {
    'counter1': 0,
    'counter2': 0,
    'counter3': 0
  },
  'third': {
    'counter1': 0,
    'counter2': 0,
    'counter3': 0
  }
}

The problem here is that each counter dictionary is not independent, so when I update one counter, all of them are updated.

The following line not only updates the counter2 of second but also updates counter2 of first and third

my_dict['second']['counter2'] += 1


{
  'first': {
    'counter1': 0,
    'counter2': 1,
    'counter3': 0
  },
  'second': {
    'counter1': 0,
    'counter2': 1,
    'counter3': 0
  },
  'third': {
    'counter1': 0,
    'counter2': 1,
    'counter3': 0
  }
}

I am aware that by doing [counter_dict]*len(mylist) I am pointing all dictionaries to a single one.

Question is, how can I achieve what I need creating independent dictionaries? At the end I need to:

  • Acces each element of the list as a key
  • For each element have multiple counters that I can update independently

Thanks a lot

You can use copy.deepcopy to copy a dict and copy its contents.

import copy

Instead of [counter_dict]*len(mylist)
use:

[copy.deepcopy(counter_dict) for _ in mylist]

Try this one:

my_dict = {k: counter_dict.copy() for k in my_list}

Instead of zipping values - it's enough to iterate over keys and copy your counters to values using dict compression.

But note, that this will work only with one level counter_dict. If needed nested dictionary - use deepcopy from copy package:

from copy import deepcopy
my_dict = {k: deepcopy(counter_dict) for k in my_list}

Another aproach - using defaultdict from collections , so you dont even need to create dictionary with predefined counters:

from collections import defaultdict
my_dict = {k: defaultdict(int) for k in my_list}

使用列表推导而不是*运算符,并为列表的每个元素创建一个新字典。

my_dict = dict(zip(mylist, [dict(counter_dict) for _ in mylist])

You can go and make a function that will create a counter_dict whenever you want to assign one:

def create_counter_dict(length):
    return {'counter{}'.format(n+1) : 0 for n in range(length)}

Then when you want to assign a counter_dict to your my_dict :

my_dict = dict(zip(my_list, [create_counter_dict(3) for _ in range(len(my_list))]))

This way you don't have to make a copy of your dictionary, and you can alter this factory function to your needs.

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