itertools.izip() for not predefined count of lists - python

I have the following data structure: {'one':['a','b','c'],'two':['q','w','e'],'three':['t','u','y'],...}. So, the dictionary has variant count of keys. Each array, picked by dict's key has similar length. How I can convert this structure to following: [{'one':'a','two':'q','three':'t'},{'one':'b','two':'w','three':'y'},...]?
I think I should use itertools.izip(), but how i can apply it with not predefined count of args? Maybe something like this: itertools.izip([data[l] for l in data.keys()])?
TIA!

Not terribly elegant, but does the trick:
In [9]: [{k:v[i] for (k,v) in d.items()} for i in range(len(d.values()[0]))]
Out[9]:
[{'one': 'a', 'three': 't', 'two': 'q'},
{'one': 'b', 'three': 'u', 'two': 'w'},
{'one': 'c', 'three': 'y', 'two': 'e'}]
I can't help thinking that there's got to be a better way to phrase the i loop, but nothing comes to mind right now.
Alternatively:
In [50]: map(dict, zip(*[[(k, v) for v in l] for k, l in d.items()]))
Out[50]:
[{'one': 'a', 'three': 't', 'two': 'q'},
{'one': 'b', 'three': 'u', 'two': 'w'},
{'one': 'c', 'three': 'y', 'two': 'e'}]
Not sure if this is much of an improvement on the readability front though.

Your assessment in using izip is correct but the way of using it is not quite right
You first need to
get the items as a list of tuples (key, value), (using iteritems() method if using Py2.x or items() if using Py3.x)
create a scalar product of key and value
flatten the list (using itertools.chain)
zip it (using itertools.izip)
and then create a dict of each element
Here is the sample code
>>> from pprint import PrettyPrinter
>>> pp = PrettyPrinter(indent = 4)
>>> pp.pprint(map(dict, izip(*chain((product([k], v) for k, v in data.items())))))
[ { 'one': 'a', 'three': 't', 'two': 'q'},
{ 'one': 'b', 'three': 'u', 'two': 'w'},
{ 'one': 'c', 'three': 'y', 'two': 'e'}]
>>>

Related

How to remove subset dictionaries from list of dictionaries

I have a list of dictionaries, and some of them are subsets:
l = [
{'zero': 'zero', 'one': 'example', 'two': 'second'},
{'zero': 'zero', 'one': 'example', 'two': 'second', 'three': 'blabla'},
{'zero': 'zero'},
{'zero': 'non-zero', 'one': 'example'}, ...
]
And I want to create a new list of dictionaries that do not contain a subset of dictionaries.
res = [
{'zero': 'zero', 'one': 'example', 'two': 'second', 'three': 'blabla'},
{{'zero': 'non-zero', 'one': 'example'}, ...
]
This work around will create a new list that only contains dictionaries that are not subsets of any other dictionary in the list
res = [
d for d in l
if not any(set(d.items()).issubset(set(other.items()))
for other in l if other != d)
]
print(res)
Output:
[{'zero': 'zero', 'one': 'example', 'two': 'second', 'three': 'blabla'},
{'zero': 'non-zero', 'one': 'example'}]

Turn a list into multiple dictionaries in a list

I have a list like this:
original_list= ['A', 'B', 'C', 'D', 'E']
How would I be able to write a function to convert it into this:
converted_list= [{'A': 1}, {'B': 1}, {'C': 1}, {'D': 1}, {'E': 1}]
All the values in each dictionary are 1.
Thank you!
Use a list comprehension:
converted_list = [{s: 1} for s in original_list]

Removing inverse duplicates in dictionary python

I have a python dictionary containing some example keys and values:
{'a': ['b'],
'c': ['d'],
'x': ['y'],
'y': ['x'],
'i': ['j','k'],
'j': ['i','k']
'k': ['i','j']}
What letter the key is and which letters are values are irrelevant providing they are shown to have a relationship. I need to be able to remove any 'duplicate' key-value combination so that my dictionary would be displayed as follows.
{'a': ['b'],
'c': ['d'],
'x': ['y'],
'i': ['j','k']}
You can turn each entry to a tuple and use a set to get O(n) time.
d = {'a': ['b'],
'c': ['d'],
'x': ['y'],
'y': ['x'],
'i': ['j','k'],
'j': ['i','k'],
'k': ['i','j']}
seen = set()
to_remove = []
for key, val in d.items():
entry = tuple(sorted(val.copy() + [key]))
to_remove.append(key) if entry in seen else seen.add(entry)
for key in to_remove:
del d[key]
print(d)
Output:
{'a': ['b'], 'c': ['d'], 'x': ['y'], 'i': ['j', 'k']}
Here is a solution how you can have it in one single loop with a dict comprehension as a one liner:
{k: v for i, (k, v) in enumerate(d.items()) if not set(list(d.keys())[:i]).intersection(v)}
And if you want to have it really fast:
s = set()
dmod = {}
for k, v in d.items():
s.add(k)
if not s.intersection(v):
dmod[k] = v
Both approaches assume your dict is named d.
Result:
# {'a': ['b'], 'c': ['d'], 'x': ['y'], 'i': ['j', 'k']}
However, I have to state here that your text description does not suit the expected example. It would be nice if you could update that.
Besides that: are you aware, that the algorithm you ask for is completely order dependent? No solution which returns the result you want will work reliably prior python 3.6 without explicitely using ordered dicts.
I don't know your use case, but is it ok that applying the same algorithm to a e.g. backwards ordered dict creates a different result?
Another one liner:
>>> d = {'a': ['b'], 'c': ['d'], 'x': ['y'], 'y': ['x'], 'i': ['j','k'], 'j': ['i','k'], 'k': ['i','j']}
>>> dict({tuple(sorted((k, *v))):(k, v) for k, v in d.items()}.values())
{'a': ['b'], 'c': ['d'], 'y': ['x'], 'k': ['i', 'j']}
The inner dict is built with the sorted tuples (key, value1, value2, ...) as keys and the (key, [value1, value2, ...]) pairs as values. Obviously, for every sorted tuple, you keep the last (key, [value]) pair (this matters only if the dict keys are ordered, Python >= 3.6). Then build a dict with these (key, [value]) pair.
If you want to get only the first key-value (Python >= 3.6), just reverse the order of iteration of the original dict:
>>> dict({tuple(sorted((k, *v))):(k, v) for k, v in sorted(d.items(), reverse=True)}.values())
{'x': ['y'], 'i': ['j', 'k'], 'c': ['d'], 'a': ['b']}
If that's not clear, here's a more simple example. I want to keep the first list having a given length in a list:
>>> L = [[1], [2], [1,2], [2,3,4], [3], [5,2], [7,8,9]]
>>> {len(v): v for v in reversed(L)}
{3: [2, 3, 4], 2: [1, 2], 1: [1]}
We see that only the first value is kept:
[*[1]*, [2], *[1,2]*, *[2,3,4]*, [3], [5,2], [7,8,9]]
Because this first value is the last to be added to the dict and overwrite the next one (or previous one in reverse order).

how to create a dictionary of list of dictionary

I need to create a dictionary of list of dictionaries or if there is any other way of achieving the below requirement:
i have a set of keys let say
keys = [1,2,3,4,5] (dont consider this as list but i am just showing i have let say 5 keys)
for each key i will have a set of key value pair so something lime below:
d = {
1:{
{'one': 'test', 'two': 'new', 'three': 'dummy'}
{'one': 'testtest', 'two': 'newnew', 'three': 'dummyextra'}
{'one': 'newvalue', 'two': 'newvalue2', 'three': 'newvalue4'}
}
2:{
{'one': 'test1', 'two': 'new1', 'three': 'dummy1'}
{'one': 'testtest2', 'two': 'newnew2', 'three': 'dummyextra2'}
{'one': 'newvalue3', 'two': 'newvalue23', 'three': 'newvalue43'}
}
1:{
{'one': 'test', 'two': 'new', 'three': 'dummy'}
{'one': 'testtest', 'two': 'newnew', 'three': 'dummyextra'}
{'one': 'newvalue', 'two': 'newvalue2', 'three': 'newvalue4'}
}
}
All the inner and outer dictionaries will be forming through loops.
If because of unique key the above is not possible than what will be the alternate solution to get the data in above format (list of dictionaries or dictionary of lists or anything else?).
With above my main agenda is i will have a unique tag that will be the key of outer dictionary and using that tag i will be creating one HTML header,
under that header i will b populating the data i.e. multiple links and that internal data has to come from inner dictionary from the example.
So in this example i have an html page with header title 1 and under this header i will have 3 links that wil come from inner dictionary.
Than i will have header 2 and again 3 links under it and so on.
Kindly help me to achieve this.
Thanks,
You just have to represent lists with [] not {} and don't forget the commas (,) to separate the elements:
d = {
1:[
{'one': 'test', 'two': 'new', 'three': 'dummy'},
{'one': 'testtest', 'two': 'newnew', 'three': 'dummyextra'},
{'one': 'newvalue', 'two': 'newvalue2', 'three': 'newvalue4'}
],
2:[
{'one': 'test1', 'two': 'new1', 'three': 'dummy1'},
{'one': 'testtest2', 'two': 'newnew2', 'three': 'dummyextra2'},
{'one': 'newvalue3', 'two': 'newvalue23', 'three': 'newvalue43'}
],
3:[
{'one': 'test', 'two': 'new', 'three': 'dummy'},
{'one': 'testtest', 'two': 'newnew', 'three': 'dummyextra'},
{'one': 'newvalue', 'two': 'newvalue2', 'three': 'newvalue4'}
]
}
Try to guess something similar to your input (dlist) just to how how to build a dict using a list as a default value and appending data:
dlist = [[2, {'two': 'two1'}], [1, {'one': 'one1'}], [1, {'one': 'one2'}], [2, {'two': 'two2'}] ]
res = {}
for item in dlist:
res.setdefault(item[0], list()).append(item[1])
print(res)
#=> {1: [{'one': 'one1'}, {'one': 'one2'}], 2: [{'two': 'two1'}, {'two': 'two2'}]}

Mapping strings in a nested data structure

Mapping two datastructures consisting of lists and dictionaries. The mapping from data should be recursively applied to the payload structure.
These are my inputs
data = {
'a': 'Apple',
'b': 'Ball',
'c': 'Cat',
'd': 'Dog',
'e': 'Egg',
'f': 'Fish',
'g': 'Goat',
'h': 'House',
'i': 'Ice-Cream',
'j': 'Jaguar',
'k': 'Key',
'l': 'Lock',
'm': 'Map'
}
and
payload = {
'PI': [
{
'one': 'a',
'two': 'b',
'three': 'c',
'four': {
'five': 'd',
'six': 'e',
'seven': 'f',
'eight': 'g'
}
}, {
'nine': 'h',
'ten': 'i',
'eleven': 'j',
'twelve': 'k'
}
]
}
Expected output:
payload = {
'PI': [
{
'one': 'Apple',
'two': 'Ball',
'three': 'Cat',
'four': {
'five': 'Dog',
'six': 'Egg',
'seven': 'Fish',
'eight': 'Goat'
}
}, {
'nine': 'House',
'ten': 'Ice-Cream',
'eleven': 'Jaguar',
'twelve': 'Key'
}
]
}
This my attempt at creating the mapping but it is not working
def mapping(payload):
for k,v in payload.items():
if(isinstance(v,dict)):
mapping(v)
elif(isinstance(v,list)):
for item in v:
mapping(item)
else:
try:
v = data[v]
except KeyError:
pass
return payload
I get this instead:
{
'PI': [
{
'four': {
'eight': 'g',
'five': 'd',
'seven': 'f',
'six': 'e'
},
'one': 'a',
'three': 'c',
'two': 'b'
},
{
'eleven': 'j',
'nine': 'h',
'ten': 'i',
'twelve': 'k'
}
]
}
Nothing has been replaced.
You can indeed use recursion; recurse for list values, and dictionary elements, and just map directly for everything else. Do not forget to return the result; the recursive function creates new dictionaries and lists:
def replace_strings(value, mapping):
if isinstance(value, list):
return [replace_strings(v, mapping) for v in value]
if isinstance(value, dict):
return {replace_strings(k, mapping): replace_strings(v, mapping)
for k, v in value.items()}
return mapping.get(value, value)
Demo:
>>> pprint(replace_strings(payload, data))
{'PI': [{'four': {'eight': 'Goat',
'five': 'Dog',
'seven': 'Fish',
'six': 'Egg'},
'one': 'Apple',
'three': 'Cat',
'two': 'Ball'},
{'eleven': 'Jaguar',
'nine': 'House',
'ten': 'Ice-Cream',
'twelve': 'Key'}]}
Your code had several issues:
You ignored the return value of any recursive call.
You returned the original input, unaltered.

Categories

Resources