Create an array of dictionaries from a Python list

10,297

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).

Share:
10,297
Daniel Bourke
Author by

Daniel Bourke

Updated on June 04, 2022

Comments

  • Daniel Bourke
    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_
    iz_ over 5 years
    @aws_apprentice You must have a quicker computer, because my tests show your edit at 57.8 µs.
  • iz_
    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_
    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_
    iz_ over 5 years
    %timeit list(map(score_vals, vals)) isn't actually timing the whole computation, only a small portion of it.