Сопоставить два списка в один список словарей - PullRequest
6 голосов
/ 28 октября 2008

Представьте, что у меня есть следующие списки питонов:

keys = ['name', 'age']
values = ['Monty', 42, 'Matt', 28, 'Frank', 33]

Есть ли прямой или хотя бы простой способ составить следующий список словарей?

[
    {'name': 'Monty', 'age': 42},
    {'name': 'Matt',  'age': 28},
    {'name': 'Frank', 'age': 33}
]

Ответы [ 8 ]

13 голосов
/ 28 октября 2008

Вот почтовый путь

def mapper(keys, values):
    n = len(keys)
    return [dict(zip(keys, values[i:i + n]))
            for i in range(0, len(values), n)]
3 голосов
/ 28 октября 2008

Это не красиво, но вот одна строка, использующая понимание списка, почтовый индекс и степпинг:

[dict(zip(keys, a)) for a in zip(values[::2], values[1::2])]
2 голосов
/ 28 октября 2008

В ответе Конрад Рудольф

Zip почти делает то, что вы хотите; к сожалению, вместо того, чтобы ездить на велосипеде по более короткому списку, он ломается. Возможно, есть связанная функция, которая циклически повторяется?

Вот способ:

keys = ['name', 'age']
values = ['Monty', 42, 'Matt', 28, 'Frank', 33]
iter_values = iter(values)
[dict(zip(keys, iter_values)) for _ in range(len(values) // len(keys))]

Я не буду называть это Pythonic (я думаю, что это слишком умно), но это может быть то, что ищут.

Нет смысла зацикливать список keys, используя itertools.cycle(), поскольку каждый обход keys соответствует созданию одного словаря.

РЕДАКТИРОВАТЬ: Вот еще один способ:

def iter_cut(seq, size):
    for i in range(len(seq) / size):
        yield seq[i*size:(i+1)*size]

keys = ['name', 'age']
values = ['Monty', 42, 'Matt', 28, 'Frank', 33]
[dict(zip(keys, some_values)) for some_values in iter_cut(values, len(keys))]

Это гораздо более питонно: есть читаемая служебная функция с ясной целью, а остальная часть кода естественно вытекает из нее.

2 голосов
/ 28 октября 2008

zip почти делает то, что вы хотите; к сожалению, вместо того, чтобы ездить на велосипеде по более короткому списку, он ломается. Возможно, есть связанная функция, которая циклически повторяется?

$ python
>>> keys = ['name', 'age']
>>> values = ['Monty', 42, 'Matt', 28, 'Frank', 33]
>>> dict(zip(keys, values))
{'age': 42, 'name': 'Monty'}

/ EDIT: О, вы хотите список из dict . Следующие работы (в том числе и благодаря Петру):

from itertoos import cycle

keys = ['name', 'age']
values = ['Monty', 42, 'Matt', 28, 'Frank', 33]

x = zip(cycle(keys), values)
map(lambda a: dict(a), zip(x[::2], x[1::2]))
2 голосов
/ 28 октября 2008

Тупой путь, но тот, который сразу приходит мне в голову:

def fields_from_list(keys, values):
    iterator = iter(values)
    while True:
        yield dict((key, iterator.next()) for key in keys)

list(fields_from_list(keys, values)) # to produce a list.
1 голос
/ 28 октября 2008

Еще одна попытка, возможно, более тупая, чем первая:

def split_seq(seq, count):
    i = iter(seq)
    while True:
        yield [i.next() for _ in xrange(count)]

>>> [dict(zip(keys, rec)) for rec in split_seq(values, len(keys))]
[{'age': 42, 'name': 'Monty'},
 {'age': 28, 'name': 'Matt'},
 {'age': 33, 'name': 'Frank'}]

Но решать вам, тупее ли это.

1 голос
/ 28 октября 2008

Вот мой простой подход. Кажется, она близка к идее @Cheery, за исключением того, что я уничтожаю список ввода.

def pack(keys, values):
  """This function destructively creates a list of dictionaries from the input lists."""
  retval = []
  while values:
    d = {}
    for x in keys:
      d[x] = values.pop(0)
    retval.append(d)
  return retval
0 голосов
/ 29 октября 2008
[dict(zip(keys,values[n:n+len(keys)])) for n in xrange(0,len(values),len(keys)) ]

UG-Leee. Я бы не хотел видеть код, который выглядит так. Но это выглядит правильно.

def dictizer(keys, values):
   steps = xrange(0,len(values),len(keys))
   bites = ( values[n:n+len(keys)] for n in steps)
   return ( dict(zip(keys,bite)) for bite in bites )

Все еще немного некрасиво, но имена помогают понять это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...