Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I need to convert two list into a dictionary. I have two list named A and B,
A = [[1,2,3] [2,3,4] [1,4,5] [1,3,4]]
the values in A (list of list) will be unique
B = [[10,13,23] [22,21,12] [5,34,23] [10,9,8]]
the length of both list will be same
I need the result like
C = [['1' :10 , '2' :13, '3': 23] ['2':22, '3':21, '4':12] ['1':5, '4':34, '5':23] ['1':10, '3':9, '4':8]]
I tried the dict method but it is throwing me an error saying list is un hashable type. Please let me know how to do this. Im new to python.
It's hard to be sure, but I'm guessing your problem is this:
If a and b were just flat lists of numbers, all you'd have to do is this:
dict(zip(a, b))
And I'm assuming that's similar to what you wrote. But that doesn't work here. Those aren't lists of numbers, they're list of lists. And you don't to get back a dict, you want a list of dicts.
So, you're asking Python to create a dict whose keys are the sub-lists of a, and whose values are the sub-lists of b. That's an error because lists can't be keys, but it wouldn't be useful even if that weren't an issue.
To actually do this, you need to not only zip up a and b, but also zip up their sublists, and pass those sub-zips, not the main zip, to dict. Like this:
[dict(zip(suba, subb)) for (suba, subb) in zip(a, b)]
I think you want C to be a list of dictionaries. Here's a straightforward way to do that.
def combine(keys, values):
"generate a dictionary from keys and values"
out = {}
for k,v in zip(keys,values):
out[k] = v
return out
def combine_each(keys, values):
"for each pair of keys and values, make a dictionary"
return [combine(klist, vlist) for (klist,vlist) in zip(keys,values)]
C = combine_each(A,B)
Alternative:
>>> A = [[1,2,3], [2,3,4], [1,4,5], [1,3,4]]
>>> B = [[10,13,23], [22,21,12], [5,34,23], [10,9,8]]
>>> [{k:v for k, v in zip(sa, sb)} for (sa, sb) in zip(A, B)]
[{1: 10, 2: 13, 3: 23}, {2: 22, 3: 21, 4: 12}, {1: 5, 4: 34, 5: 23}, {1: 10, 3: 9, 4: 8}]
Related
I want to make a single list with two dictionaries in it using two, two dimensional lists. Note that each element should have to be paired to the element of the second list.
a = [[1,2,3],[4,5,6]]
b = [[7,8,9],[10,11,12]]
c = dict(zip(a,b))
is not working because list is not hash-able.
Then I need the out put as
c = [{1:7, 2:8, 3:9}, {4:10, 5:11, 6:12}]
You want something like the following:
c = [dict(zip(keys, vals)) for keys, vals in zip(a, b)]
Here we use a list comprehension to zip and cast to a dict for each inner list in the original lists a and b.
Alternatively, we could flatten out the comprehension further, to get:
c = [{k: v for k, v in zip(keys, vals)} for keys, vals in zip(a, b)]
Both are equivalent, its just a matter of style.
Output:
>>> print(c)
[{1: 7, 2: 8, 3: 9}, {4: 10, 5: 11, 6: 12}]
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
Having this two arrays in Python:
a = [ ['a',1], ['b',2], ['c',3] ]
b = [ ['a',10], ['b',20], ['c',30], ['d',40] ]
Is it possible to combine them into a single array like this?
output = [ ['a',1,10], ['b',2,20], ['b',3,30], ['c',0,40] ]
Since 'c' doesn't exist in the first array, first integer should be 0.
Thank you.
As stated in the comments, if missing values can be at any place, you cannot use zip or zip_longest. Here I use dicts for joining values:
a = [ ['a',1], ['b',2], ['c',3] ]
b = [ ['a',10], ['b',20], ['c',30], ['d',40] ]
d1, d2 = dict(a), dict(b)
d = {k: [d1.get(k, 0), d2.get(k, 0)] for k in d1.keys() | d2.keys()}
print( sorted([k, *v] for k, v in d.items()) ) # use custom key= to sort them to right order (or don't use sort if you don't need it)
Prints:
[['a', 1, 10], ['b', 2, 20], ['c', 3, 30], ['d', 0, 40]]
It would seem to me that picking a dictionary for your datatype would make more sense than lists, but if you need to use lists, this is an approach:
the lists in the original lists, are really just tuples, matching key to value; a dictionary would make more sense here
you want one list in the result for each key in the original lists
the lists in the result list, are really just 3-tuples, matching key to first and second value
you want the value from the first list for each key (or 0 if none) as the first value
you want the value from the first list for each key (or 0 if none) as the second value
da = {l[0]: l[1] for l in a}
db = {l[0]: l[1] for l in b}
result = [
[k, da[k] if k in da else 0, db[k] if k in db else 0]
for k in sorted(set(list(da.keys()) + list(db.keys())))
]
print(result)
Note that the sorted() is in there to preserve order. If alphabetical order isn't guaranteed, you can just combine the keys and dedupe using something like this:
def dedupe(seq):
seen = set()
seen_add = seen.add
return [x for x in seq if not (x in seen or seen_add(x))]
This question already has answers here:
Extract a subset of key-value pairs from dictionary?
(14 answers)
Filter dict to contain only certain keys?
(22 answers)
Closed 5 years ago.
Dictionary:
d = {'a':[2,3,4,5],
'b':[1,2,3,4],
'c':[5,6,7,8],
'd':[4,2,7,1]}
I want to have d_new which containes only b and c items.
d_new = {'b':[1,2,3,4],
'c':[5,6,7,8]}
I want a scalable solution
EDIT:
I also need a method to create a new dictionary by numbers of items:
d_new_from_0_to_2 = {'a':[2,3,4,5],
'b':[1,2,3,4]}
If you want a general way to pick particular keys (and their values) from a dict, you can do something like this:
d = {'a':[2,3,4,5],
'b':[1,2,3,4],
'c':[5,6,7,8],
'd':[4,2,7,1]}
selected_keys = ['a','b']
new_d = { k: d[k] for k in selected_keys }
Gives:
{'a': [2, 3, 4, 5], 'b': [1, 2, 3, 4]}
I think that in Python 2.6 and earlier you would not be able to use a dict comprehension, so you would have to use:
new_d = dict((k,d[k]) for k in selected_keys)
Is this what you want?
new_d = dict(b=d.get('b'), c=d.get('c'))
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
If I have a dictionary of dictionaries, of arbitrary depth, how could I list all of the keys that are in the dictionary, at a given depth? or get a list of the keys in the dictionary and their depths?
For example, a simple dictionary would be:
dict_o_dicts = {'a': {1:'bob', 2: 'fred', 3: 'henry'},
'b': {2:'fred',3: 'henry', 4: 'pascale'}
}
and I'd like a command that does something along the lines of:
print keys_at_depth(dict_o_dicts, 0)
would return: ['a', 'b'] and print keys_at_depth(dict_o_dicts, 1)
would return [1,2,3,4]
I can recursively walk the dictionary to find the maximum depth of the dictionary, but as soon as I try and report both the depth and the key values I end up breaking the recursion.
Thanks
This routine will recursively return a dictionary of sets of the keys at each depth:
def keys_by_depth(dict_, depth=0, output=None):
if output is None:
output = {}
if not depth in output:
output[depth] = set()
for key in dict_:
output[depth].add(key)
if isinstance(dict_[key], dict):
keys_by_depth(dict_[key], depth+1, output)
return output
Gives the output:
{0: {'b', 'a'}, 1: {1, 2, 3, 4}}
Note that this will work with a mix of dictionary and non-dict values at each level. For only keys at a given depth, you can call and access in one go:
>>> print(keys_by_depth(dict_o_dicts)[1])
{1, 2, 3, 4}
The assumption is that, all levels have valid dicts
dict_o_dicts = {'a': {1:'bob', 2: 'fred', 3: 'henry'},
'b': {2:'fred',3: 'henry', 4: 'pascale'} }
from itertools import chain
def keys_at_depth(d, l):
if l == 0: return d.keys()
elif l > 0: return set(chain.from_iterable([keys_at_depth(d[k], l - 1) for k in d]))
print keys_at_depth(dict_o_dicts, 1)
Output
set([1, 2, 3, 4])
Recursive approach:
def key_at_depth(dct, dpt):
if dpt > 0:
return [
key
for subdct in dct.itervalues()
for key in key_at_depth(subdct, dpt - 1)
]
else:
return dct.keys()
dict_o_dicts = {
'a': {1: 'bob', 2: 'fred', 3: 'henry'},
'b': {2: 'fred', 3: 'henry', 4: 'pascale'},
}
key_at_depth(dict_o_dicts, 0)
Out[69]: ['a', 'b']
key_at_depth(dict_o_dicts, 1)
Out[70]: [1, 2, 3, 2, 3, 4]
It seems you are working with a tree structure and you want obtain the nodes given a level. Reading your post, I realized may exists more dictionaries at the same level. So the solution I post here returns all the keys of all dictionaries at the given level.
keys=[]
def keys_at_level(tree, level):
# TODO: Eliminate that ugly global var keys.
if level == 0: # Adjust this contition to your needs (0 or 1)
# Calculate keys.
global keys
keys.extend(tree.keys())
else:
# Iter throught values and ask for dicts.
values = tree.values()
for value in values:
if isinstance(value, dict):
keys_at_level(value, level-1)
keys_at_level(tree, 0)
print keys
# If you don't want duplicates just do:
keys = set(keys)
I have 2 lists of dictionaries. List A is 34,000 long, list B is 650,000 long. I am essentially inserting all the List B dicts into the List A dicts based on a key match. Currently, I am doing the obvious, but its taking forever (seriously, like a day). There must be a quicker way!
for a in listA:
a['things'] = []
for b in listB:
if a['ID'] == b['ID']:
a['things'].append(b)
from collections import defaultdict
dictB = defaultdict(list)
for b in listB:
dictB[b['ID']].append(b)
for a in listA:
a['things'] = []
for b in dictB[a['ID']]:
a['things'].append(b)
this will turn your algorithm from O(n*m) to O(m)+O(n), where n=len(listA), m=len(listB)
basically it avoids looping through each dict in listB for each dict in listA by 'precalculating' what dicts from listB match each 'ID'
Here's an approach that may help. I'll leave it to you to fill in the details.
Your code is slow because it is a O(n^2) algorithm, comparing every A against every B.
If you sort each of listA and listB by id first (these are O(nlogn)) operations, then you can iterate easily through the sorted versions of A and B (this will be in linear time).
This approach is common when you have to do external merges on very large data sets. Mihai's answer is better for internal merging, where you simply index everything by id (in memory). If you have the memory to hold these additional structures, and dictionary lookup is constant time, that approach will likely be faster, not to mention simpler. :)
By way of example let's say A had the following ids after sorting
acfgjp
and B had these ids, again after sorting
aaaabbbbcccddeeeefffggiikknnnnppppqqqrrr
The idea is, strangely enough, to keep indexes into A and B (I know that does not sound very Pythonic). At first you are looking at a in A and a in B. So you walk through B adding all the a's to your "things" array for a. Once you exhaust the a's in B, you move up one in A, to c. But the next item in B is b, which is less than c, so you have to skip the b's. Then you arrive at a c in B, so you can start adding into "things" for c. Continue in this fashion until both lists are exhausted. Just one pass. :)
I'd convert ListA and ListB into dictionaries instead, dictionaries with ID as the key. Then it is a simple matter to append data using python's quick dictionary lookups:
from collections import defaultdict
class thingdict(dict):
def __init__(self, *args, **kwargs):
things = []
super(thingdict,self).__init__(*args, things=things, **kwargs)
A = defaultdict(thingdict)
A[1] = defaultdict(list)
A[2] = defaultdict(list, things=[6]) # with some dummy data
A[3] = defaultdict(list, things=[7])
B = {1: 5, 2: 6, 3: 7, 4: 8, 5: 9}
for k, v in B.items():
# print k,v
A[k]['things'].append(v)
print A
print B
This returns:
defaultdict(<class '__main__.thingdict'>, {
1: defaultdict(<type 'list'>, {'things': [5]}),
2: defaultdict(<type 'list'>, {'things': [6, 6]}),
3: defaultdict(<type 'list'>, {'things': [7, 7]}),
4: {'things': [8]},
5: {'things': [9]}
})
{1: 5, 2: 6, 3: 7, 4: 8, 5: 9}