Python : Get list by index not key in defaultdict - python

I'm new to python and I have become stuck on a data type issue.
I have a script which looks a bit like this
dd = defaultdict(list)
for i in arr:
dd[color].append(i)
which creates a default dict which resembles something along the lines of
dd = [('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
However I need to now access the first list([2,4]). I have tried
print(dd[0])
but this game me the following output
[][][]
I know the defaultdict has data in it as I have printed it in its entirety. However other than access the first item by its dictionary index I don't know how to access it. However, other than access the list by the dictionary key I don't know how to get it. However, I don't know the name of the key until I populate the dict.
I have thought about creating a list of lists rather than a defaultdict but being able to search via key is going to be really usefull for another part of the code so I would like to maintain this data structure if possible.
is there a way to grab the list by an index number or can you only do it using a key?

You can get a list of keys, pick the key by index, then access that key.
print(dd[dd.keys()[0]])

Note that a dictionary in Python is an unordered collection. This means that the order of keys is undefined. Consider the following example:
from collections import defaultdict
d = defaultdict (int)
d['a'] = 1
d['b'] = 2
d['c'] = 3
d['d'] = 4
d['e'] = 5
print (d)
My Python2 gives:
defaultdict(<type 'int'>, {'a': 1, 'c': 3, 'b': 2, 'e': 5, 'd': 4})
Python3 output is different by the way:
defaultdict(<class 'int'>, {'c': 3, 'b': 2, 'a': 1, 'e': 5, 'd': 4})
So, you will have to use some other means to remember the order in which you populate the dictionary. Either maintain a separate list of keys (colors) in the order you need, or use OrderedDict.

Related

Duplicate dictionary keys in initialization - Python

Is it correct to say that the rightmost/last key-value pair for a given key would always be considered if there are multiple identical keys when initializing a dictionary ?
Example :
Dict = {'A': 5, 'B': 6, 'A': 10}
Will Dict['A'] always be 10 in all python implementations? Where does python enforce this ?
You know that python dict can't contain duplicate keys. So
Dict = {'A': 5, 'B': 6)
Dict.update({'A': 10})
print(Dict['A'])
will result in the last value assigned to the key A:
Output:
10
So the situation is almost like that, python goes through the dictionary during evaluation, and keeps the last value assigned to the keys.
I know dict aren't ordered, but:
That doesn't mean python will jump back and forth on the dict when parsing the dict into memory.
It will parse through it from left to right to get the collect the data, but it stores the dict without keeping its order.
Python dict can not have duplicate keys. if you try to add the same key again, it will update the existing key with the new value.
Dict = {'A': 5, 'B': 6, 'A': 10}
print(Dict)
{'A': 10, 'B': 6}
the above statement execution is similar to below:
Dict['A'] = 5
print(Dict)
{'A'=5}
Dict['B'] = 6
print(Dict)
{'A'=5, 'B'=6}
Dict['A'] = 10
print(Dict)
{'A'=10, 'B'=6}

Insertion order and Duplicate Keys in Dictionary

I'm using python 3.7.
I have a dictionary something like this.
dict = { 'a' :2 , 'a' :1 , 'b':3 , 'c':4}
print(dict)
O/P ={'a' : 1 , 'b' :2 , 'c':3 }
Now In python 3.7 dictionary must maintain insertion order .So expected o/p will be {'a':2 , 'b':3 , 'c' :4} , but ('a',2) is being removed from dictionary instead of('a',1) .Why is this happening ??Is there any rule for removing duplicate keys in python ??
From the Python documentation:
The main operations on a dictionary are storing a value with some key and extracting the value given the key. It is also possible to delete a key:value pair with del. If you store using a key that is already in use, the old value associated with that key is forgotten. It is an error to extract a value using a non-existent key.
See: https://docs.python.org/3/tutorial/datastructures.html
Maintaining insertion order is concerned with different keys:
>>> dct = {'a': 1, 'b': 2} # do NOT shadow built-in name 'dict'
>>> print(dct)
{'a': 1, 'b': 2}
# and not
{'b': 2, 'a': 1} # which was totally possible before Python3.6
When receiving multiple values for the same key, the last one provided wins:
>>> dct = {'a': 3, 'a': 1, 'b': 2}
>>> print(dct)
{'a': 1, 'b': 2}
This is similar to the following scenario:
>>> dct = {}
>>> dct['a'] = 3
>>> dct['a'] = 1
>>> dct['b'] = 2
Would you expect dct['a'] to be 3 now because of the "insertion order"? Certainly not!
The value assigned to a key can be anything and even duplicated since it merely a value. Keys however, are similar to a variable name. Like in many programming languages, if a variable name is used again in the same scope or method, the first variable and its value is overwritten by the second since it is more recent.
In this case it may be more appropriate to to assign a different key (think of keys as identifiers) to the same value if that is your wish. Like this
dict = { 2: 'a', 1: 'a', 3:'b', 4:'c'}
print(dict)
O/P = {1: 'a', 2: 'a', 3: 'b', 4: 'c'}

How to merge two or more dict into one dict with retaining multiple values of same key as list?

I have two or more dictionary, I like to merge it as one with retaining multiple values of the same key as list. I would not able to share the original code, so please help me with the following example.
Input:
a= {'a':1, 'b': 2}
b= {'aa':4, 'b': 6}
c= {'aa':3, 'c': 8}
Output:
c= {'a':1,'aa':[3,4],'b': [2,6], 'c': 8}
I suggest you read up on the defaultdict: it lets you provide a factory method that initializes missing keys, i.e. if a key is looked up but not found, it creates a value by calling factory_method(missing_key). See this example, it might make things clearer:
from collections import defaultdict
a = {'a': 1, 'b': 2}
b = {'aa': 4, 'b': 6}
c = {'aa': 3, 'c': 8}
stuff = [a, b, c]
# our factory method is the list-constructor `list`,
# so whenever we look up a value that doesn't exist, a list is created;
# we can always be sure that we have list-values
store = defaultdict(list)
for s in stuff:
for k, v in s.items():
# since we know that our value is always a list, we can safely append
store[k].append(v)
print(store)
This has the "downside" of creating one-element lists for single occurences of values, but maybe you are able to work around that.
Please find below to resolve your issue. I hope this would work for you.
from collections import defaultdict
a = {'a':1, 'b': 2}
b = {'aa':4, 'b': 6}
c={'aa':3, 'c': 8}
dd = defaultdict(list)
for d in (a,b,c):
for key, value in d.items():
dd[key].append(value)
print(dd)
Use defaultdict to automatically create a dictionary entry with an empty list.
To process all source dictionaries in a single loop, use itertools.chain.
The main loop just adds a value from the current item, to the list under
the current key.
As you wrote, for cases when under some key there is only one item,
you have to generate a work dictionary (using dictonary comprehension),
limited to items with value (list) containing only one item.
The value of such item shoud contain only the first (and only) number
from the source list.
Then use this dictionary to update d.
So the whole script can be surprisingly short, as below:
from collections import defaultdict
from itertools import chain
a = {'a':1, 'b': 2}
b = {'aa':4, 'b': 6}
c = {'aa':3, 'c': 8}
d = defaultdict(list)
for k, v in chain(a.items(), b.items(), c.items()):
d[k].append(v)
d.update({ k: v[0] for k, v in d.items() if len(v) == 1 })
As you can see, the actual processing code is contained in only 4 (last) lines.
If you print d, the result is:
defaultdict(list, {'a': 1, 'b': [2, 6], 'aa': [4, 3], 'c': 8})

Filter list of dictionaries with duplicate values at a certain key

I have a dictionary as follows:
dic=[{'a':1,'b':2,'c':3},{'a':9,'b':2,'c':2},{'a':5,'b':1,'c':2}]
I would like to filter out those dictionaries with recurring values for certain keys, such as in this case the key 'b' which has duplicate values in the first and second dictionaries in the list. I would like to remove the second entry
Quite simply, I would like my filtered list to look as follows:
filt_dic=[{'a':1,'b':2,'c':3},{'a':5,'b':1,'c':2}]
Is there a pythonic way to do this?
Use another dictionary (or defaultdict) to keep track of what values you have already seen for what keys. This dictionary will hold one set (for fast lookup) for each key of the original dict.
dic=[{'a':1,'b':2,'c':3},{'a':9,'b':2,'c':2},{'a':5,'b':1,'c':2}]
seen = defaultdict(set)
filt_dic = []
for d in dic:
if not any(d[k] in seen[k] for k in d):
filt_dic.append(d)
for k in d:
seen[k].add(d[k])
print(filt_dic)
Afterwards, filt_dic is [{'a': 1, 'c': 3, 'b': 2}, {'a': 5, 'c': 2, 'b': 1}] and seen is {'a': set([1, 5]), 'c': set([2, 3]), 'b': set([1, 2])}).

Not getting the same result when inverting a dictionary twice

I'm trying to invert a simple dictionary like:
{'a' : 1, 'b' : 2, 'c' : 3, 'd' : 4}
I'm using this function:
def invert(d):
return dict([(x,y) for y,x in d.iteritems()])
Now when I invert my dictionary, everything works out fine. When I invert it twice however, I get:
{'a': 1, 'c': 3, 'b': 2, 'd': 4}
which is not in the same order as the dictionary I started with. Is there a problem with my invert function? Sorry I'm kinda new to python, but thanks for any help!
That is correct, dictionaries are unordered in python
from another so answer answer:
CPython implementation detail: Keys and values are listed in an
arbitrary order which is non-random, varies across Python
implementations, and depends on the dictionary’s history of insertions
and deletions.
from the docs:
It is best to think of a dictionary as an unordered set of key: value
pairs, with the requirement that the keys are unique (within one
dictionary). A pair of braces creates an empty dictionary: {}. Placing
a comma-separated list of key:value pairs within the braces adds
initial key:value pairs to the dictionary; this is also the way
dictionaries are written on output.
Python dictionaries are unsorted by design.
You can use collections.OrderedDict instead if you really need this behaviour.
Try running this code:
d = {
'a' : 1, 'b' : 2,
'c' : 3, 'd' : 4
}
def invert(d):
return dict([(x,y) for y,x in d.iteritems()])
print d
d = invert(d)
print d
d = invert(d)
print d
This is the output:
{'a': 1, 'c': 3, 'b': 2, 'd': 4}
{1: 'a', 2: 'b', 3: 'c', 4: 'd'}
{'a': 1, 'c': 3, 'b': 2, 'd': 4}
As you can see, it technically is the same dictionary, but when you declare it, it is unordered.

Categories

Resources