I am doing a boolean retrieval project, the first phase is indexing. I am trying to build an inverted index now. Say I got a sorted list like following: how can I merge the items
list = [('a',1),('a',2),('a',3),('b',1),('b',2),('b',3)...]
such that I can get a dictionary like the following and it remains sorted:
dict = {'a':[1,2,3], 'b':[1,2,3]...}, thx a lot
You can do it like this:
>>> import collections
>>> mylist = [('a',1),('a',2),('a',3),('b',1),('b',2),('b',3)]
>>> result = collections.defaultdict(list)
>>> for item in mylist:
result[item[0]].append(item[1])
>>> dict(result)
{'a': [1, 2, 3], 'b': [1, 2, 3]}
defaultdict(list) creates a dictionary in which keys are initialised upon first access to an object created using the callable passed as the argument (in this case list). It avoids having to check whether the key already exists or not.
The last line converts the defaultdict to a normal dict - it is not strictly necessary as defaultdict behaves like a normal dictionary too.
Values are appended to each key in the same order as the original list. However, the keys themselves will not be ordered (this is a property of dictionaries).
Update: if you need the dictionary keys to remain sorted as well, you can do this:
>>> import collections
>>> mylist = [('a',1),('a',2),('c',1),('c',2),('b',1),('b',2)]
>>> result = collections.OrderedDict()
>>> for item in mylist:
if item[0] not in result:
result[item[0]] = list()
result[item[0]].append(item[1])
>>> result
OrderedDict([('a', [1, 2]), ('c', [1, 2]), ('b', [1, 2])])
>>> result.keys()
['a', 'c', 'b']
Obviously, you cannot use dict(result) in this case as dict does not maintain any specific key order.
Related
Im trying to print specific value in this dictionary compiled of several list.
the_dic = {'k1':[1,2,3,{'tricky':['oh','man','inception',{'target':[1,2,3,'hello']}]}]}
Expected output: hello
Can i expand from this simple code below?
print(the_dic["k1"])
You can keep indexing further by referring to the specific index (of the list) [3] or further keys in the dictionary!
This works because the result of each indexing or key reference returns the inner value, which exposes its own methods for indexing or referring to its keys (or a single value, ending your chain!) depending on the inner type
Continuing the chain little further
>>> d = {'k1':[1,2,3,{'tricky':['oh','man','inception',{'target':[1,2,3,'hello']}]}]}
>>> d["k1"]
[1, 2, 3, {'tricky': ['oh', 'man', 'inception', {'target': [1, 2, 3, 'hello']}]}]
>>> d["k1"][3]
{'tricky': ['oh', 'man', 'inception', {'target': [1, 2, 3, 'hello']}]}
>>> d["k1"][3]["tricky"]
['oh', 'man', 'inception', {'target': [1, 2, 3, 'hello']}]
Offering a simpler example, it may be clearer still
>>> d = {'a': {'b': [1,2,3]}}
>>> d['a']['b'] # list referenced by key 'b' within key 'a' of d
[1, 2, 3]
>>> d['a']['b'][0] # first member of the very innermost list
1
I think for your desired output your final code will be:
the_dic = {'k1':[1,2,3,{'tricky':['oh','man','inception',{'target':[1,2,3,'hello']}]}]}
print(the_dic['k1'][3]['tricky'][3]['target'][3])
Result:
hello
A helper recursive function such as this should do the trick:
def get_last_val(d):
if isinstance(d, list):
return get_last_val(d[-1])
if isinstance(d, dict):
return get_last_val(d.popitem()[1])
return d
Example:
>>> get_last_val(the_dic)
'hello'
I'm using Aiohttp's implementation of multidict().
Take this:
>>> d = MultiDict[('a', 1), ('b', 2), ('a', 3)])
>>> d
<MultiDict {'a': 1, 'b': 2, 'a': 3}>
I want to convert d to a regular dictionary where duplicate key values are appended into a list such as this:
{'a': [1, 3], 'b': 2}
Is there an elegant way to convert this? Other than a loop through items and a lot of logical conditions?
It doesnt look like multidicts have an inbuilt function for a straight conversion, but you can use the .keys() function to iterate through the multidict and copy the values into a fresh dictionary.
new_dict = {}
for k in set(multi_dict.keys()):
new_dict[k] = multi_dict.getall(k)
Two interesting things here - we need to make a set of the multidict keys function call to remove duplicates, and multidicts have a .getall() function that returns a list of all values associated with duplicate keys.
EDIT for single value cases:
new_dict = {}
for k in set(multi_dict.keys()):
k_values = multi_dict.getall(k)
if len(k_values) > 1:
new_dict[k] = k_values
else:
new_dict[k] = k_values[0]
I want to create a dictionary where the value is a list. Now with every new incoming key I want to start a new list.
If I simply try to append to the dictionary key value it shows an error, since the value is not yet declared a list, and I can't do this at the beginning since I don't know how many keys I'll have.
For example (Note that for MyDict keyList is variable, something not previously known)
keyList = [['a',1,2],['b',3,4]]
MyDict={}
for key in keyList:
MyDict[key[0]].append(key[1:])
What I want to create is:
MyDict={'a': [[1, 2]], 'b': [[3, 4]]}
Is there a way to do this?
You can use setdefault.
Instead of MyDict[key[0]].append(key[1:])
Try using MyDict.setdefault(key[0],[]).append(key[1:])
So when you are trying to append value, if the list doesn't exist it will make a default list and then append value to it
What you need is defaultdict, which is supplied with Python exactly for this purpose:
keyList = [['a',1,2],['b',3,4]]
MyDict=defaultdict(list)
for key in keyList:
MyDict[key[0]].append(key[1:])
print(MyDict)
Output
defaultdict(<class 'list'>, {'b': [[3, 4]], 'a': [[1, 2]]})
defaultdict gets in its constructor a function which is called without arguments to create default elements. list without arguments creates an empty list.
defaultdict behaves in all other ways like a normal dictionary.
If, nevertheless, in the end you want a simple dict, then convert it using dict:
print(dict(MyDict))
gives
{'b': [[3, 4]], 'a': [[1, 2]]}
Use collections.defaultdict. Example:
from collections import defaultdict
d = defaultdict(lambda: [])
d['key'].append('value to be add in list')
Sidenote: Defaultdict takes a callable argument, which means that you can also create your dict in this way:
defaultdict(list)
I am trying to build a dict from a set of unique values to serve as the keys and a zipped list of tuples to provide the items.
set = ("a","b","c")
lst 1 =("a","a","b","b","c","d","d")
lst 2 =(1,2,3,3,4,5,6,)
zip = [("a",1),("a",2),("b",3),("b",3),("c",4),("d",5)("d",6)
dct = {"a":1,2 "b":3,3 "c":4 "d":5,6}
But I am getting:
dct = {"a":1,"b":3,"c":4,"d":5}
here is my code so far:
#make two lists
rtList = ["EVT","EVT","EVT","EVT","EVT","EVT","EVT","HIL"]
raList = ["C64G","C64R","C64O","C32G","C96G","C96R","C96O","RA96O"]
# make a set of unique codes in the first list
routes = set()
for r in rtList:
routes.add(r)
#zip the lists
RtRaList = zip(rtList,raList)
#print RtRaList
# make a dictionary with list one as the keys and list two as the values
SrvCodeDct = {}
for key, item in RtRaList:
for r in routes:
if r == key:
SrvCodeDct[r] = item
for key, item in SrvCodeDct.items():
print key, item
You don't need any of that. Just use a collections.defaultdict.
import collections
rtList = ["EVT","EVT","EVT","EVT","EVT","EVT","EVT","HIL"]
raList = ["C64G","C64R","C64O","C32G","C96G","C96R","C96O","RA96O"]
d = collections.defaultdict(list)
for k,v in zip(rtList, raList):
d[k].append(v)
You may achieve this using dict.setdefault method as:
my_dict = {}
for i, j in zip(l1, l2):
my_dict.setdefault(i, []).append(j)
which will return value of my_dict as:
>>> my_dict
{'a': [1, 2], 'c': [4], 'b': [3, 3], 'd': [5, 6]}
OR, use collections.defaultdict as mentioned by TigerhawkT3.
Issue with your code: You are not making the check for existing key. Everytime you do SrvCodeDct[r] = item, you are updating the previous value of r key with item value. In order to fix this, you have to add if condition as:
l1 = ("a","a","b","b","c","d","d")
l2 = (1,2,3,3,4,5,6,)
my_dict = {}
for i, j in zip(l1, l2):
if i in my_dict: # your `if` check
my_dict[i].append(j) # append value to existing list
else:
my_dict[i] = [j]
>>> my_dict
{'a': [1, 2], 'c': [4], 'b': [3, 3], 'd': [5, 6]}
However this code can be simplified using collections.defaultdict (as mentioned by TigerhawkT3), OR using dict.setdefault method as:
my_dict = {}
for i, j in zip(l1, l2):
my_dict.setdefault(i, []).append(j)
In dicts, all keys are unique, and each key can only have one value.
The easiest way to solve this is have the value of the dictionary be a list, as to emulate what is called a multimap. In the list, you have all the elements that is mapped-to by the key.
EDIT:
You might want to check out this PyPI package: https://pypi.python.org/pypi/multidict
Under the hood, however, it probably works as described above.
Afaik, there is nothing built-in that supports what you are after.
I want to make know if there is a command that can do this:
>>>A=dict()
>>>A[1]=3
>>>A
{1:3}
>>>A[1].add(5) #This is the command that I don't know if exists.
>>>A
{1:(3,5)}
I mean, add another value to the same key without quiting the old value added.
It is possible to do this?
You could make the dictionary values into lists:
>>> A = dict()
>>> A[1] = [3]
>>> A
{1: [3]}
>>> A[1].append(5) # Add a new item to the list
>>> A
{1: [3, 5]}
>>>
You may also be interested in dict.setdefault, which has functionality similar to collections.defaultdict but without the need to import:
>>> A = dict()
>>> A.setdefault(1, []).append(3)
>>> A
{1: [3]}
>>> A.setdefault(1, []).append(5)
>>> A
{1: [3, 5]}
>>>
A defaultdict of type list will create an empty list in case you access a key that does not exist in the dictionary so far. This often leads to quite elegant code.
>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> d[1].append(3)
>>> d[1].append(2)
>>> d
defaultdict(<type 'list'>, {1: [3, 2]})
Using a defaultdict eliminates the "special case" of the initial insert.
from collections import defaultdict
A = defaultdict(list)
for num in (3,5):
A[1].append(num)
Like others pointed out, store the values in a list, but remember to check if the key is in the dictionary to determine whether you need to append or create a new list for that key...
A = dict()
if key in A: A[key].append(value)
else: A[key] = [value]