Reputation: 1019
Hi I am looking to iterate over a Python dictionary where each key has a list of values, I am looking to either create a new list/dictionary where I have separated each value[x] or directly do stuff with the separated values.
here's a simplified example of the dictionary I have:
all_parameters = {"first": ["1a","1b","1c"], "second": ["2a","2b","2c"], "third": ["3a","3b","3c"]}
I am looking to separate the values like this (either by creating a new dictionary or list or directly doing stuff with the separated values).
grouped_parameters = [{"first": "1a", "second": "2a", "third": "3a"},
{"first": "1b", "second": "2b", "third": "3b"},
{"first": "1c", "second": "2c", "third": "3c"}]
I am insure how to iterate correctly over each key:value pair.
i = 0
for k, v in all_parameters.items():
for item in v:
# stuck here
i+=1
Eventually the 'stuff' I am looking to do is convert each output (e.g. '{"first": "1a", "second": "2a", "third": "3a"}') into a string so that I can post each parameter group to a cell in a table, so ideally i'd prefer to do this dynamically instead of creating a new dictionary.
Any help would be greatly appreciated.
Upvotes: 3
Views: 2667
Reputation: 55469
The items in a plain dict aren't ordered *, so you need to be careful when converting a dict to a string if you want the fields to be in a certain order.
This code uses a tuple containing the key strings in the order we want them to be in in the output dict strings.
all_parameters = {
"first": ["1a","1b","1c"],
"second": ["2a","2b","2c"],
"third": ["3a","3b","3c"],
}
# We want keys to be in this order
all_keys = ("first", "second", "third")
# Assumes all value lists are the same length.
for t in zip(*(all_parameters[k] for k in all_keys)):
a = ['"{}": "{}"'.format(u, v) for u, v in zip(all_keys, t)]
print('{' + ', '.join(a) + '}')
output
{"first": "1a", "second": "2a", "third": "3a"}
{"first": "1b", "second": "2b", "third": "3b"}
{"first": "1c", "second": "2c", "third": "3c"}
We first use a generator expression (all_parameters[k] for k in all_keys)
which yields the value lists from all_parameters
in the order specified by all_keys
. We pass those lists as args to zip
using the *
"splat" operator. So for your example data, it's equivalent to calling zip
like this:
zip(["1a","1b","1c"], ["2a","2b","2c"], ["3a","3b","3c"])
zip
effectively transposes the iterables you pass it, so the result of that call is an iterator that produces these tuples:
('1a', '2a', '3a'), ('1b', '2b', '3b'), ('1c', '2c', '3c')
We then loop over those tuples one by one, with the for t in zip(...)
, so on the first loop t
gets the value ('1a', '2a', '3a')
, then ('1b', '2b', '3b')
, etc.
Next we have a list comprehension that zips the value strings up with the corresponding key string and formats them into a string with double-quotes around each key and value string. We then join those strings together with commas and spaces as separators (and add brace characters) to make our final dict strings.
* Actually in Python 3.6 plain dicts do retain insertion order, but that is currently an implementation detail, and it should not be relied upon.
Upvotes: 1
Reputation: 10359
If there's a chance of the lists being of different length, you could use map
with None
like so:
all_parameters = {"first": ["1a", "1b", "1c", "1d"], "second": ["2a", "2b", "2c"], "third": ["3a", "3b", "3c"]}
final = [dict(zip(all_parameters.keys(), values)) for values in map(None, *all_parameters.values())]
print final
map(None, *all_parameters.values())
gives you a tuple of the values for each key at each index - e.g. ('1a', '2a', '3a')
, and by zipping this to the keys and creating a dictionary, we get the required combination.
Note: this will only work in Python 2.x as map
changed in 3.x. For Python 3.x we can use itertools.zip_longest
:
from itertools import zip_longest
all_parameters = {"first": ["1a", "1b", "1c", "1d"], "second": ["2a", "2b", "2c"], "third": ["3a", "3b", "3c"]}
final = [dict(zip(all_parameters.keys(), values)) for values in zip_longest(*all_parameters.values())]
print(final)
In both cases we get:
[{'second': '2a', 'third': '3a', 'first': '1a'}, {'second': '2b', 'third': '3b', 'first': '1b'}, {'second': '2c', 'third': '3c', 'first': '1c'}, {'second': None, 'third': None, 'first': '1d'}]
Upvotes: 1
Reputation: 78670
Assuming all lists have the same length:
>>> length = len(next(all_parameters.itervalues()))
>>> [{k:v[i] for k,v in all_parameters.iteritems()} for i in range(length)]
[{'second': '2a', 'third': '3a', 'first': '1a'}, {'second': '2b', 'third': '3b', 'first': '1b'}, {'second': '2c', 'third': '3c', 'first': '1c'}]
In Python 3, use len(next(iter(all_parameters.values())))
and items
instead of iteritems
.
(The iterator shenanigans are done because you don't need a list of all the dictionary values if you only want the length of an arbitrary value-list.)
Upvotes: 3
Reputation: 11
I'm not sure if this is what you want but
for i in range(len(all_parameters['first'])):
for position in all_parameters:
print(position+" "+all_parameters[position][i])
gives an output like this
first 1a second 2a third 3a first 1b second 2b third 3b first 1c second 2c third 3c
This will work only if each dictionary element has a list the same size as the first one.
Upvotes: 0