Related
Let's assume I have:
a placeholder string "aabbaaa"
and a dictionary: {'A': 'a', 'B': 'a', 'C': 'b', 'D': 'a', 'E': 'b', 'F': 'a', 'G': 'b'}.
How can I create in python all possible permutations from the dictionary keys for the placeholder string?
The expected result would, for example, be:
AACCAAA, AACCAAB, AACCABA, ... AACEAA, AACEAA, AAEEAA ... , FFGGFFF etc.
The solution could be:
>>> import itertools
>>> from collections import defaultdict
>>> dict_ = defaultdict(list)
>>> input = "ab"
>>> _dict = {'A': 'a', 'B': 'a', 'C': 'b', 'D': 'a', 'E': 'b', 'F': 'a', 'G': 'b'}
>>> for k,v in _dict.items():
... dict_[v].append(k)
...
>>> _iterables = [dict_[character] for character in input]
>>> output = [''.join(tup) for tup in itertools.product(*_iterables)]
set(['BE', 'AC', 'BG', 'AE', 'AG', 'BC', 'DG', 'DE', 'DC', 'FC', 'FE', 'FG'])
Let me know if it helps!!
You can build all the permutation with backtracking.
At first the dict would be more useful if reversed, so do it:
from collections import defaultdict
orig_str = "aabbaaa"
d = {'A': 'a', 'B': 'a', 'C': 'b', 'D': 'a', 'E': 'b', 'F': 'a', 'G': 'b'}
reverse_d = defaultdict(list)
for k, el in d.items():
reverse_d[el].append(k)
And here we have reverse_d = {'a': ['A', 'B', 'D', 'F'], 'b': ['C', 'E', 'G']}
Next we can write our backtracking function that for any character of the string will put the possibilities in order:
def permut(orig_str, index, chars_till_now):
if index == len(orig_str):
print("".join(chars_till_now))
return
chars = chars_till_now[:]
chars.append("")
for possibility in reverse_d[orig_str[index]]:
chars[-1] = possibility
permut(orig_str, index+1, chars)
You can modify the function to save the permutation rather than print or pass a specific dictionary rather than use one global; it depends on what you need.
To call the function just:
permut(orig_str, 0, [])
Given a pandas Series of dict values with str keys:
Series
------
{'a': 1, 'b' : 2, 'c' : 3}
{'b': 3, 'd': 5}
{'d': 7, 'e': 7}
How can the Series be scanned to retrieve a set of the dictionary keys? The resulting output would be a plain python set:
{'a', 'b', 'c', 'd', 'e'}
Thank you in advance for your consideration and response.
Use list comprehension with flattening and convert to sets:
a = set([y for x in s for y in x])
print (a)
{'e', 'a', 'd', 'c', 'b'}
Or use itertools.chain.from_iterable:
from itertools import chain
a = set(chain.from_iterable(s))
Maybe this:
s = pd.Series(...)
a = set(list(pd.DataFrame(s.tolist())))
# {'a', 'e', 'b', 'c', 'd'}
I need to write a function that accepts a list of lists representing friends for each person and need to convert it into a dictionary.
so an input of [['A','B'],['A','C'],['A','D'],['B','A'],['C','B'],['C','D'],['D','B'],['E']] should return {A:[B,C,D],B:[A],C:[B,D],D:[B],E:None}
Input:
[['A','B'],['A','C'],['A','D'],['B','A'],['C','B'],['C','D'],['D','B'],['E']]
Expected Output:
{A:[B,C,D],B:[A],C:[B,D],D:[B],E:None}
Currently I am trying the following:
s=[['A','B'],['A','C'],['A','D'],['B','A'],['C','B'],['C','D'],['D','B'],['E']]
output=dict.fromkeys((set([x[0] for x in s])),[ ])
for x in s:
if len(x)>1:
output[x[0]].append(x[1])
else:
output[x[0]].append(None)
But the output is giving me all values for every key rather than returning only the corresponding values
The output i am getting is:
{
'A': ['B', 'C', 'D', 'A', 'B', 'D', 'B', None],
'B': ['B', 'C', 'D', 'A', 'B', 'D', 'B', None],
'C': ['B', 'C', 'D', 'A', 'B', 'D', 'B', None],
'D': ['B', 'C', 'D', 'A', 'B', 'D', 'B', None],
'E': ['B', 'C', 'D', 'A', 'B', 'D', 'B', None]
}
You can iterate through the key-value pairs in the list of lists, but unpack the value as a list to accommodate the possible lack of a value:
s = [['A','B'],['A','C'],['A','D'],['B','A'],['C','B'],['C','D'],['D','B'],['E']]
output = {}
for k, *v in s:
if v:
output.setdefault(k, []).extend(v)
else:
output[k] = None
output becomes:
{'A': ['B', 'C', 'D'], 'B': ['A'], 'C': ['B', 'D'], 'D': ['B'], 'E': None}
Or if you don't mind that keys without a value get an empty list instead of None, you can simply do:
output = {}
for k, *v in s:
output.setdefault(k, []).extend(v)
output would then become:
{'A': ['B', 'C', 'D'], 'B': ['A'], 'C': ['B', 'D'], 'D': ['B'], 'E': []}
The issue is the list you feed to dict.keys is only one reference across keys.
Your desired result is inconsistent. I recommend you choose an empty list for 'E', however much it seems None is more appropriate. With this adjusted requirement, you can use collections.defaultdict.
from collections import defaultdict
L = [['A','B'],['E','C'],['A','D'],['B','A'],['C','B'],['C','D'],['D','B'],['E']]
dd = defaultdict(list)
for lst in L:
if len(lst) > 1:
dd[lst[0]].append(lst[1])
else:
dd[lst[0]]
print(dd)
defaultdict(list,
{'A': ['B', 'C', 'D'],
'B': ['A'],
'C': ['B', 'D'],
'D': ['B'],
'E': []})
You should use a common dict comprehension to initiate the dict:
output = {x[0]: [] for x in s}
dict.fromkeys gives all keys the identical referential value. With a mutable value that is a problem. The comprehension will give each key an independent list object, in addition to being more readable.
One of the way to solve this is as given below:
friend_combi = [['A','B'],['A','C'],['A','D'],['B','A'],['C','B'],['C','D'],['D','B'],['E']] # Input to be processed
final_dict = {} #Empty dict to store result
for i in friend_combi: # loop through each element in list
if final_dict.get(i[0]): #if data present in dict then append else add
final_dict[i[0]].append(i[1])
else:
final_dict[i[0]] = [i[1]] if i[1:] else None #check if value exist in list else save None
print (final_dict)
#Output --> {'A': ['B', 'C', 'D'], 'B': ['A'], 'C': ['B', 'D'], 'D': ['B'], 'E': None}
I hope this helps :)
You can define a function named get_dictionary() as the below code shows.
>>> def get_dictionary(l):
... d = {}
... for arr in l:
... if len(arr) == 2:
... key = arr[0]
... if key in d:
... d[key].append(arr[1])
... else:
... d[key] = [arr[1]]
... else:
... d[key] = None
... return d
...
>>> l = [['A','B'], ['A','C'], ['A','D'], ['B','A'], ['C','B'], ['C','D'], ['D','B'], ['E']]
>>>
>>> get_dictionary(l)
{'A': ['B', 'C', 'D'], 'B': ['A'], 'C': ['B', 'D'], 'D': None}
>>>
Pretty printing the dictionary as JSON.
>>> import json
>>>
>>> d = get_dictionary(l)
>>>
>>> print(json.dumps(d, indent=4))
{
"A": [
"B",
"C",
"D"
],
"B": [
"A"
],
"C": [
"B",
"D"
],
"D": null
}
>>>
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)
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))