Create an array of dictionaries from a Python list
Solution 1
One-liner using comprehension:
[{'value': k, 'score': v} for k, v in [my_list[i: i + 2] for i in range(0, len(my_list), 2)]]
[{'score': 2.75, 'value': 35}, {'score': 3.45, 'value': 67}]
Using your original attempt:
[{'value': k, 'score': v} for k,v in zip(my_list[::2], my_list[1::2])]
Another more verbose way
from operator import itemgetter
getters = [itemgetter(slice(i, i + 2)) for i in range(0, len(my_list), 2)]
vals = [g(my_list) for g in getters]
def score_vals(s):
k, v = s
return {'value': k, 'score': v}
list(map(score_vals, vals))
Solution 2
You're really close with the zip
version. You just need to make the object and specify the keys.
my_list = [35, 2.75, 67, 3.45]
[{'value': v, 'score': s} for v, s in zip(my_list[::2], my_list[1::2])]
result:
[{'value': 35, 'score': 2.75}, {'value': 67, 'score': 3.45}]
Solution 3
d = map(dict, map(lambda t:zip(('value','score'),t), zip(my_list[::2], my_list[1::2])))
print(list(d))
Solution 4
Try this:
my_list = [35, 2.75, 67, 3.45]
list_of_dicts = [{'value': k, 'score': v} for k, v in zip(iter(my_list), iter(my_list))]
print(list_of_dicts)
Output:
[{'value': 35, 'score': 2.75}, {'value': 67, 'score': 3.45}]
A little timing comparison between my solution and the solutions by others that use list slicing:
In [1]: my_list = [35, 2.75, 67, 3.45] * 100 # making it longer for better testing results
In [2]: def zip_with_slice():
...: return [{'value': v, 'score': s} for v, s in zip(my_list[::2], my_list[1::2])]
...:
In [3]: def zip_with_iter():
...: return [{'value': k, 'score': v} for k, v in zip(iter(my_list), iter(my_list))]
...:
In [4]: %timeit zip_with_slice()
56.5 µs ± 1.27 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [5]: %timeit zip_with_iter()
93 µs ± 2.99 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
As you can see, my solution using iterators is quite a bit (5-6x) faster than solutions using slicing.
Solution 5
In your second attempt, do score: i + 1. In the loop do for i in range(0, len(my_list), 2).
Daniel Bourke
Updated on June 04, 2022Comments
-
Daniel Bourke almost 2 years
I want to turn a list of interspersed values into an array of dictionaries.
I'm trying to make a list of prediction values in Python capable to be used with a JSON API. Once I have the dictionary, I'll use
json.dumps
on it.my_list = [35, 2.75, 67, 3.45] # in form of: (value, score, value, score)
Ideal outcome:
my_array_of_dicts = [{'value':35, 'score':2.75}, {'value':67 'score':3.45}]
Here's what I've tried.
First attempt:
d = dict(zip(my_list[::2], my_list[1::2]))
And it produces...
> {35: 2.75, 67: 3.45}
I'm not sure how to get custom keys. Or have each pair as its own dictionary.
Second attempt:
[{'value':i, 'score':i} for i in my_list]] > [{'value':35, 'score':35}, {'value':2.75, 'score':2.75}, {'value':67, 'score':67}, {'value':3.45, 'score':3.45}]
It's close but it doesn't account for every second value being a score.
-
iz_ over 5 years@aws_apprentice You must have a quicker computer, because my tests show your edit at
57.8 µs
. -
iz_ over 5 years@aws_apprentice I found the reason. I'm testing with the original list
* 100
for more accurate results, while you are testing with the original list. This makes sense, as your solution doesn't look like an improvement. -
iz_ over 5 years@aws_apprentice Are you sure you are using the new, longer list? Also, your
timeit
doesn't seem fair, because you are doing the actual computation beforehand. -
iz_ over 5 years
%timeit list(map(score_vals, vals))
isn't actually timing the whole computation, only a small portion of it.