How to convert a dictionary into a flat list? - python

Given a Python dict like:
{
'a': 1,
'b': 2,
'c': 3
}
What's an easy way to create a flat list with keys and values in-line? E.g.:
['a', 1, 'b', 2, 'c', 3]

Since you are using Python 2.7, I would recommend using dict.iteritems or dict.viewitems and list comprehension, like this
>>> [item for pair in d.iteritems() for item in pair]
['a', 1, 'c', 3, 'b', 2]
>>> [item for pair in d.viewitems() for item in pair]
['a', 1, 'c', 3, 'b', 2]
dict.iteritems or dict.viewitems is better than dict.items because, they don't create a list of key-value pairs.
If you are wondering how you can write portable code which would be efficient in Python 3.x as well, then you just iterate the keys like this
>>> [item for k in d for item in (k, d[k])]
['a', 1, 'c', 3, 'b', 2]

In [39]: d = {
'a': 1,
'b': 2,
'c': 3
}
In [40]: list(itertools.chain.from_iterable(d.items()))
Out[40]: ['b', 2, 'a', 1, 'c', 3]
Note that dicts are unordered, which means that the order in which you enter keys is not always the order in which they are stored. If you want to preserve order, you might be looking for an ordereddict

You can use sum:
>>> d = {'a': 1, 'b': 2, 'c': 3}
>>> sum(d.items(), tuple())
('a', 1, 'c', 3, 'b', 2)

res_list = []
for k, v in d:
res_list.append(k).append(v)

Related

Count every instance of an item in a list of lists and sum them

In Python 3.x, I have a list of lists:
[['a','b','c'], ['a', 'c'], ['c', 'd'] ]
I saw this answer, but it only applies to a single list. How would I do this for a list of lists? My desired output would be a sorted list (or a sortable list) of the frequency of a particular item in a list.
Something like:
{a: 2, b: 1, c: 3, d: 1 }
You could use itertools.chain(*l) as an input to the Counter.
>>> l= [['a','b','c'], ['a', 'c'], ['c', 'd'] ]
>>> Counter(itertools.chain(*l))
Counter({'c': 3, 'a': 2, 'b': 1, 'd': 1})
This may be solved using Counter. Counter creates a dictionary of the counts of the elements in the lists.
L = [['a','b','c'], ['a', 'c'], ['c', 'd'] ]
>>> from collections import Counter
>>> d = Counter()
>>> for sub in L:
d.update(sub)
>>> d
Counter({'c': 3, 'a': 2, 'b': 1, 'd': 1})
You can use Counter from collections to do this very efficiently:
In [161]: from collections import Counter
...:
...: count = Counter()
...:
...: lists = [['a','b','c'], ['a', 'c'], ['c', 'd']]
...:
...: for sublist in lists:
...: count += Counter(sublist)
...:
...: print(count)
Counter({'c': 3, 'a': 2, 'b': 1, 'd': 1})
This is "one-line-able" using python's builtin sum:
In [163]: from collections import Counter
...: lists = [['a','b','c'], ['a', 'c'], ['c', 'd']]
...:
...: count = sum(map(Counter, lists), start=Counter())
...:
...: print(count)
Counter({'c': 3, 'a': 2, 'b': 1, 'd': 1})
You can flatten the list and use Counter. If your list is arbitrarily nested.
from collections import Counter
def flatten(lst):
if not isinstance(lst,list):
return [lst]
else:
return [j for i in lst for j in flatten(i)]
print(Counter(flatten([['a','b','c'], ['a', 'c'], ['c', 'd'] ])))
#Counter({'c': 3, 'a': 2, 'b': 1, 'd': 1})
You can do by itering in each sublist:
dict={}
for sublist in list:
for item in sublist:
if item in dict.keys():
dict[item] +=1
else:
dict[item] =1
you can flatten your list and apply collections.Counter:
from collections import Counter
l = [['a','b','c'], ['a', 'c'], ['c', 'd'] ]
Counter((e for i in l for e in i))

Merging two lists into dictionary while keeping duplicate data in python

Hi, I want to merge two lists into one dictionary. Suppose I have two lists such as below
list_one = ['a', 'a', 'c', 'd']
list_two = [1,2,3,4]
and I want my dictionary to be like this
{'a': 1, 'a': 2, 'c': 3, 'd': 4}
As of right now, I have this following code
print dict(zip(['a', 'a', 'c', 'd'], [1,2,3,4]))
But the output from above code is this
{'a': 2, 'c': 3, 'd': 4}
How can I make it to this output?
{'a': 1, 'a': 2, 'c': 3, 'd': 4}
Thanks
A defining characteristic of dicts is that each key is unique. Thus, you can't have two 'a' keys. Otherwise, what would my_dict['a'] return?
Since keys in dictionaries are unique, getting {'a': 1, 'a': 2, 'c': 3, 'd': 4} is impossible here for regular python dictionaries, since the key 'a' can only occur once. You can however have a key mapped to multiple values stored in a list, such as {'a': [1, 2], 'c': [3], 'd': [4]}.
One option is to create a defaultdict to do this easily for you:
from collections import defaultdict
list_one = ['a', 'a', 'c', 'd']
list_two = [1, 2, 3, 4]
d = defaultdict(list)
for key, value in zip(list_one, list_two):
d[key].append(value)
print(dict(d))
Which outputs:
{'a': [1, 2], 'c': [3], 'd': [4]}
Dictionaries must have unique keys, so you would have to change your requirement. How about a list of tuples as a workaround?
l = list(zip(['a', 'a', 'c', 'd'],[1,2,3,4]))
print(l)
With the resulting being:
[('a', 1), ('a', 2), ('c', 3), ('d', 4)]
You can easily iterate over and unpack like so:
for k, v in l:
print("%s: %s" % (k, v))
which produces:
a: 1
a: 2
c: 3
d: 4
If you want it hashable, you can create a tuple of tuples like so:
l = tuple(zip(['a', 'a', 'c', 'd'],[1,2,3,4]))
From the documentation for dictionaries:
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.
Dictionary has unique keys. If you need the value of 'a' separately store the zipped data in a list or you can use list in values part of the dict and store the values as:
{'a': [1,2],'c': [3], 'd': [4]}
As other answers have pointed out, dictionaries have unique keys, however, it is possible to create a structure to mimic the behavior you are looking for:
class NewDict:
def __init__(self, *values):
self.values = list(zip(*values))
def __getitem__(self, key):
return [b for a, b in sorted(self.values, key=lambda x:x[0]) if a == key]
def __repr__(self):
return "{}({})".format(self.__class__.__name__, "{"+', '.join("{}:{}".format(*i) for i in sorted(self.values, key=lambda x:x[0]))+"}")
list_one = ['a', 'a', 'c', 'd']
list_two = [1,2,3,4]
d = NewDict(list_one, list_two)
print(d['a'])
print(d)
Output:
[1, 2]
NewDict({a:1, a:2, c:3, d:4})
You have two options :
either you use tuple :
list_one = ['a', 'a', 'c', 'd']
list_two = [1,2,3,4]
print(list(map(lambda x,y:(x,y),list_one,list_two)))
output:
[('a', 1), ('a', 2), ('c', 3), ('d', 4)]
Second option is use this pattern:
dict_1={}
for key,value in zip(list_one,list_two):
if key not in dict_1:
dict_1[key]=[value]
else:
dict_1[key].append(value)
print(dict_1)
output:
{'a': [1, 2], 'd': [4], 'c': [3]}
The keys in dictionary should be unique.
According to python documentation:
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).
link
to the documentation

One line iteration through dictionaries in dictionaries

G2 = {'a': {'c': 1, 'b': 1}, 'b': {'a': 1, 'c': 1}}
b = G2.values()
for i in b:
for key, value in i.items():
list.append(key)
#result: ['c', 'b', 'a', 'c']
Can I get the same result but using a list generator?
I tried it like this:
list2 = [key for key, value in i.items() for i in b]
#but i get: ['a', 'a', 'c', 'c']
just chain the dictionary values (aka keys) using itertools.chain.from_iterable, and convert to list to print the result:
import itertools
G2 = {'a': {'c': 1, 'b': 1}, 'b': {'a': 1, 'c': 1}}
#['c', 'b', 'a', 'c']
result = list(itertools.chain.from_iterable(G2.values()))
print(result)
result:
['c', 'b', 'c', 'a']
note that the order is not guaranteed as you're iterating on dictionary keys.
Variant without using itertools with flattening double loop inside comprehension (which is probably closer to your attempt):
result = [x for values in G2.values() for x in values]

How to merge two lists by index

I have two lists:
i = ['a', 'b', 'c']
x = [1,2,3]
i need to produce such dictionary:
xxx = { 'a': [a, 1],
'b': [b, 2],
'c': [c, 3]}
I have done this:
for indx in i:
for indx2 in x:
xxx.update({indx: [indx, indx2]})
but obvioulsy it doesnt work
Using dict comprehension:
>>> i = ['a', 'b', 'c']
>>> x = [1,2,3]
>>> {key: [key, value] for key, value in zip(i, x)}
{'a': ['a', 1], 'c': ['c', 3], 'b': ['b', 2]}
how about this, if tuple can be the value of your dict.
i= ['a', 'b', 'c']
x= [1, 2, 3]
dict(zip(i,zip(i,x)))
{'a': ('a', 1), 'b': ('b', 2), 'c': ('c', 3)}

What is an alternative to sorted() in this situation? Or can this be managed?

Considering the following dictionary...
d = {'ab': 3, 'aa': 3, 'b': 4, 'c': 2, 'a': 1}
>>>sorted(d, key=d.get, reverse=True)[:2]
['b', 'ab']
Using sorted, the goal was to produce the keys associated with the two highest values. Here is where I am having trouble getting it to do what I want: When two values are tied, the key which appears first alphabetically should be chosen. So in this case what I actually want returned is ['b', 'aa'] since 'aa' and 'ab' both have the value of 3. The values of the dictionary will also always be positive if that helps.
How about:
>>> d = {'ab': 3, 'aa': 3, 'b': 4, 'c': 2, 'a': 1}
>>> sorted(d, key=lambda x: (-d[x], x))
['b', 'aa', 'ab', 'c', 'a']
>>> sorted(d, key=lambda x: (-d[x], x))[:2]
['b', 'aa']
or
>>> sorted(d, key=lambda x: (-d[x], x.lower()))[:2]
['b', 'aa']
depending on how much you care about the case.
You could also take advantage of the fact that the sort is stable and do it in two passes:
>>> sorted(sorted(d), key=d.get, reverse=True)
['b', 'aa', 'ab', 'c', 'a']
d = {'ab': 3, 'aa': 3, 'b': 4, 'c': 2, 'a': 1}
print sorted(d, key = lambda x: (-d[x], x))[:2]
Output
['b', 'aa']
Since we return tuples as keys, comparisons will happen like mentioned here
sorted(d, key=lambda dx: (-d[dx], d))[:2]
If you don't mind reshaping your data:
>>> import itertools
>>> d = {'ab': 3, 'aa': 3, 'b': 4, 'c': 2, 'a': 1}
>>> sorted(d, key=lambda k:(d[k], k), reverse=True)
['b', 'ab', 'aa', 'c', 'a']
>>> cols = {}
>>> for k,v in d.items():
... if v not in cols:
... cols[v] = []
... cols[v].append(k)
...
>>> cols
{1: ['a'], 2: ['c'], 3: ['ab', 'aa'], 4: ['b']}
>>> list(itertools.chain.from_iterable([cols[k] for k in sorted(cols, reverse=True)]))
['b', 'ab', 'aa', 'c', 'a']
>>> list(itertools.chain.from_iterable([cols[k] for k in sorted(cols, reverse=True)]))[:2]
['b', 'ab']
Try
key=lambda x:(-d[x], x)
Edited for negative value
If you didn't have a requirement to sort by key if the count is tied, then Counter is the correct data structure to solve this problem.
from collections import Counter
d = {'ab': 3, 'aa': 3, 'b': 4, 'c': 2, 'a': 1}
cnt = Counter(d)
d.most_common(2)
Adding the requirement to sort by key means:
sorted(d.most_common(2), key=lambda k,v: (v,k))

Categories