So I have a list of tuples of the form:
my_list=[('a','aa','aaa',0),('a','aa','aab',1),('a','ab','aba',2)]
And I need it to convert it to a nested dictionary:
out={'a':{'aa':{'aaa':0,'aab':1},'ab':{'aba':2}}}
The crucial piece of my setting is that I do not know in advance the length of the tuples in my_list (4 is just an example). Is there an easy way to generalize the cases I saw in other answers (e.g. Python list of tuples to nested dict or Convert a list of variable length Tuples into Dictionary) beyond the fixed 3-element tuples they use?
I made various attempts with recursive functions but I do not have anything close to a solution.
Just loop over the first keys, setting aside the last pair of items which will be a key-value pair, and set dictionaries in-between (using setdefault here, but you could do that part manually):
result = {}
for *keys, last_key, value in my_list:
current = result
for key in keys:
current = current.setdefault(key, {})
current[last_key] = value
Just to be explicit by what I mean by "manually" (I guess I should rather say "explicitly"):
result = {}
for *keys, last_key, value in my_list:
current = result
for key in keys:
if key not in current:
current[key] = {}
current = current[key]
current[last_key] = value
Related
i have a dictionary
dictionary = {
1:[[1,2],[3,4],[5,6],[7,8],[1,2]],
2:[[5,6],[7,8],[1,2]],
3:[3,4],[5,6],[3,4]]
}
How can i remove duplicate list in each value of the dictionary?
output = {
1:[[3,4],[5,6],[7,8],[1,2]],
2:[[5,6],[7,8],[1,2]],
3:[3,4],[5,6]]
}
How can i remove all duplicates?
output = [[1,2],[3,4],[5,6],[7,8]]
i have tried doing for loops, like so:
for i in dictionary.values():
for j in i:
for k in i:
if j == k:
i.remove(k)
but i'm just a beginner so i'm not getting any results...
The usual way to do this is to leverage a set, which is like a dictionary that has only keys and no values. Dictionaries (and sets) rely on their keys to be "hashable," which means that you can feed the key through some hash function and get the same result every time. In Python you can call this hash function with hash(some_object), which internally invokes some_object.__hash__().
The problem with this approach is that lists are not hashable. No mutable objects (things you can change with methods like list.append or set.add or dict.union or etc) are. This means you must either check equality by hand, or mutate it into some form that is hashable, use the set, and then mutate it back. I think the latter is probably your best bet.
To that end, let's use a tuple. Tuples are just like lists except they are not idiomatically homogenous (so mixing types is common, not just technically allowed) and their order has semantic meaning. Consider an ordered pair on a plane -- it would matter deeply if the order flipped: (1, 4) is not the same point as (4, 1). They are, however, immutable and hashable.
d = {1: [[1,2],[3,4],[5,6],[7,8],[1,2]],
2: [[5,6],[7,8],[1,2]],
3: [[3,4],[5,6],[3,4]]}
# we'll use a set comprehension here because it's concise
uniques = {tuple(sublst) for lst in d.values() for sublst in lst}
result = [list(tup) for tup in uniques] # then just change them back to lists
Note that the conversion to set and back does lose all ordering. If ordering is important then you'll have to do something like iterate through every sub list, convert it to tuple, check to see if it's already been seen, and if not add it to the seen set and append it to your final list.
d = {1: [[1,2],[3,4],[5,6],[7,8],[1,2]],
2: [[5,6],[7,8],[1,2]],
3: [[3,4],[5,6],[3,4]]}
seen = set()
result = []
for lst in d.values():
for sublst in lst:
tup = tuple(sublst)
if tup not in seen:
seen.add(tup)
result.append(sublst)
I have a dictionary where the keys are integers and the values are strings. The dictionary has been sorted using key values.
I need to copy the corresponding string values (keeping the sorted order) to a list. I cannot figure out how to iterate over the dictionary.
I know the number of key-value pairs in the dictionary (let it be 'n').
Some_ordered_dict
resultant_list=[]
for i in range(n):
resultant_list.append(Some_ordered_dict[increment-key?]
The dictionary was sorted using OrderedDict from some dictionary 'dic' as follows;
od=collections.OrderedDict(sorted(dic.items()))
The essential point is that I have to display the strings values of the dictionary in the same order as they appear in the sorted dictionary.
resultant_list = [d[k] for k in sorted(d)]
The standard Python dictionary does not guarantee that items in a dictionary will be kept in any order. Next thing is that you have to iterate using a "for in" statement like such:
Some_ordered_dict
resultant_list=[]
for i in Some_ordered_dict:
resultant_list.append(Some_ordered_dict[i])
You should take a look at the ordered dict collection to ensure that the items on your dict are kept in the order that you expect.
Using the standard unordered dictionary in python you could use something like this:
resultant_list = []
for i in sorted(dict.keys()):
resultant_list.append(dict[i])
As mentioned in other posts, dictionaries do not guarantee order. One way to get a sorted list would be to created a list of tuples out of your dict's (key, value) pairs, then sort this list based n the first element(the key), as follows:
my_dict = {2: 'two', 3: 'three', 1: 'one'}
my_tuple_list = list(zip(my_dict.keys(), my_dict.values()))
my_sorted_list = sorted(my_tuple_list, key = lambda item: item[0])
resultant_list = [x[1] for x in my_sorted_list]
I get this error message:
TypeError: list indices must be integers, not list
Using this code:
def invert_networks_dict(person_to_networks):
"""
(dict of {str: list of str}) -> dict of {str: list of str})
"""
networks_to_person = []
for person in person_to_networks:
networks = person_to_networks[person]
networks_to_person[networks] = person
if not (networks in networks_to_person):
networks_to_person[networks] = person
else:
networks_to_person[networks].append[person]
How can I fix it?
You should have initialized networks_to_person as dictionary:
networks_to_person = {}
networks_to_person = []
This assigns networks_to_person to a list. However, you want it to be a dict:
networks_to_person = dict() # <--
You can also use {} (empty dict literal), but I prefer dict() because it makes your intent more explicit.
#glglgl brought up a good point in the comments (which I'll restate here for completeness).
networks_to_person[networks].append[person]
You want to call append here, not index it. Therefore, you want:
networks_to_person[networks].append(person)
Lastly, note that you can't have lists as keys to a dictionary. You can convert them to tuples (which can be keys) instead using tuple().
if you want to 'reverse' dictionary d (swap keys and values), with values being list of strings you can:
dict((tuple(val), key) for key, val in d.items())
However, you can do this only if d.values are unique, as keys in new dictionary must be unique.
Explanation:
dict() is a built-in that creates dictionary from sequence of pairs (key, value). As with every dictionary, key must be hashable.
Because we want to make values of d new keys, we need to transform them to something hashable - in this case this will be tuple. We can create it from any sequence, including lists that are values of d, with another builtin: tuple().
So what we need are pairs of keys in values from d. We can get them using d.items(). We can make this in easy way using list comprehension, additionally wrapping val in tuple, to make it hashable, so it can be used as key:
[(tuple(val), key) for key, val in d.items())] # that would create list of pairs
But if we pass something to function, we don't need to create list, we can pass similar expression as generator comprehension, so our final code looks like:
result = dict((tuple(val), key) for key, val in d.items())
Do you know that a dict as a items function
So instead of that:
networks_to_person = {}
for person in person_to_networks:
networks = person_to_networks[person]
networks_to_person[networks] = person
You can do
networks_to_person = {}
for person, networks in person_to_networks.items():
networks_to_person[networks] = person
Which can also be written as:
networks_to_person = {networks: person for person, networks in person_to_networks.items()}
I have this list:
source = ['sourceid', 'SubSourcePontiflex', 'acq_source', 'OptInSource', 'source',
'SourceID', 'Sub-Source', 'SubSource', 'LeadSource_295', 'Source',
'SourceCode', 'source_code', 'SourceSubID']
I am iterating over XML in python to create a dictionary for each child node. The dictionary varies in length and keys with each iteration. Sometimes the dictionary will contain a key that is also an item in this list. Sometimes it wont. What I want to be able to do is, if a key in the dictionary is also an item in this list then append the value to a new list. If none of the keys in the dictionary are in list source, I'd like to append a default value. I'm really having a brain block on how to do this. Any help would be appreciated.
Just use the in keyword to check for membership of some key in a dictionary.
The following example will print [3, 1] since 3 and 1 are keys in the dictionary and also elements of the list.
someList = [8, 9, 7, 3, 1]
someDict = {1:2, 2:3, 3:4, 4:5, 5:6}
intersection = [i for i in someList if i in someDict]
print(intersection)
You can just check if this intersection list is empty at every iteration. If the list is empty then you know that no items in the list are keys in the dictionary.
in_source_and_dict = set(mydict.keys()).intersection(set(source))
in_dict_not_source = set(mydict.keys()) - set(source)
in_source_not_dict = set(source) - set(mydict.keys())
Iterate over the result of which one you want. In this case I guess you'll want to iterate over in_source_not_dict to provide default values.
In Python 3, you can perform set operations directly on the object returned by dict.keys():
in_source_and_dict = mydict.keys() & source
in_dict_not_source = mydict.keys() - source
in_source_not_dict = source - mydict.keys()
This will also work in Python 2.7 if you replace .keys() by .viewkeys().
my_dict = { some values }
values = []
for s in sources:
if my_dict.get(s):
values += [s]
if not values:
values += [default]
You can loop through the sources array and see if there is a value for that source in the dictionary. If there is, append it to values. After that loop, if values is empty, append the default vaule.
Note, if you have a key, value pair in your dictionary (val, None) then you will not append the None value to the end of the list. If that is an issue you will probably not want to use this solution.
You can do this with the any() function
dict = {...}
keys = [...]
if not any(key in dict for key in keys):
# no keys here
Equivalently, with all() (DeMorgan's laws):
if all(key not in dict for key in keys):
# no keys here
I wrote the below code working with dictionary and list:
d = computeRanks() # dictionary of id : interestRank pairs
lst = list(d) # tuples (id, interestRank)
interestingIds = []
for i in range(20): # choice randomly 20 highly ranked ids
choice = randomWeightedChoice(d.values()) # returns random index from list
interestingIds.append(lst[choice][0])
There seems to be possible error because I'm not sure if there is a correspondence between indices in lst and d.values().
Do you know how to write this better?
One of the policies of dict is that the results of dict.keys() and dict.values() will correspond so long as the contents of the dictionary are not modified.
As #Ignacio says, the index choice does correspond to the intended element of lst, so your code's logic is correct. But your code should be much simpler: d already contains IDs for the elements, so rewrite randomWeightedChoice to take a dictionary and return an ID.
Perhaps it will help you to know that you can iterate over a dictionary's key-value pairs with d.items():
for k, v in d.items():
etc.