Как создать список или кортеж пустых списков в Python? - PullRequest
39 голосов
/ 07 октября 2010

Мне нужно постепенно заполнять список или кортеж списков.Что-то похожее на это:

result = []
firstTime = True
for i in range(x):
    for j in someListOfElements:
        if firstTime:
            result.append([f(j)])
        else:
            result[i].append(j)

Чтобы сделать его менее многословным и более элегантным, я подумал, что предварительно выделю список пустых списков

result = createListOfEmptyLists(x)
for i in range(x):
    for j in someListOfElements:
        result[i].append(j)

Часть preallocation isn 'Для меня это очевидно.Когда я делаю result = [[]] * x, я получаю список x ссылок на тот же список, так что вывод следующих

result[0].append(10)
print result

:

[[10], [10], [10], [10], [10], [10], [10], [10], [10], [10]]

Я могуиспользуйте цикл (result = [[] for i in range(x)]), но мне интересно, существует ли решение "без петель".

Это единственный способ получить то, что я ищу

Ответы [ 5 ]

52 голосов
/ 07 октября 2010
result = [list(someListOfElements) for _ in xrange(x)]

Это создаст x отдельных списков, каждый с копией списка someListOfElements (каждый элемент в этом списке является ссылкой, но список является копией).

Если это имеет больше смысла, рассмотрите возможность использования copy.deepcopy(someListOfElements)

Генераторы, списки и прочее считаются вполне pythonic .

7 голосов
/ 07 октября 2010

На самом деле нет способа создать такой список без цикла некоторого сортировки.Есть несколько способов скрыть цикл, как и [[]] * x скрывает цикл.Есть понимание списка, которое «скрывает» цикл в выражении (хотя, к счастью, оно все еще очевидно.) Также есть map(list, [[]]*x), который имеет два скрытых цикла (один в [[]] * x и один в map, который создает копию каждого списка, используя list().)

Также есть возможность не создавать список списков заранее.Другие ответы уже охватывают простой подход, но если это как-то не соответствует вашим потребностям, есть другие способы.Например, вы можете создать функцию, которая при необходимости добавляет пустой список в список result, и вызвать его так:

def append(L, idx, item):
    while len(L) <= idx:
        L.append([])
    L[idx].append(item)

for i in range(x):
    for j in someListOfElements:
        append(result, i, j)

Или вместо списка можно использовать collections.defaultdict(list):

import collections
result = collections.defaultdict(list)
for i in range(x):
    for j in someListOfElements:
        result[i].append(j)

Это имеет преимущество использования уже существующего типа, который является менее трудоемким, но это означает, что теперь у вас есть dict (проиндексированный целыми числами) вместо списка, который может или не может быть тем, что выхочу.Или вы можете создать класс, который ведет себя почти как список, но добавляет новые списки к себе вместо вызова IndexError, например:

import UserList
class defaultlist(UserList.UserList):
    def __getitem__(self, idx):
        while len(self) <= idx:
            self.append([])
        return UserList.UserList.__getitem__(self, idx)

result = defaultlist()
for i in range(x):
    for j in someListOfElements:
        result[i].append(j)
5 голосов
/ 07 октября 2010

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

def create(n, constructor=list):
    for _ in xrange(n):
        yield constructor()

Затем, чтобы составить список списков,

result = list(create(10))

составить список пустых диктов,

result = list(create(20, dict))

и (для полноты) составить список пустых Foos,

result = list(create(30, Foo))

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

Последняя мысль состоит в том, что, поскольку единственное требование, которое мы налагаем на constructor, это то, что оно может быть вызвано, вы можете даже передать ему все, что вы хотите, в вашем списке. Например, связанный метод, который извлекает результаты из запроса к базе данных. Это довольно полезные маленькие три строки кода.

4 голосов
/ 07 октября 2010

Почему бы не сделать это простым, просто добавив список в соответствующий цикл

result = []
for i in range(x):
    result.append([])
    for j in someListOfElements:
        result[i].append(j)

[Редактировать: Добавление примера]

>>> someListOfElements = ['a', 'b', 'c']
>>> x = 3
>>> result = []
>>> for i in range(x):
...     result.append([])
...     for j in someListOfElements:
...         result[i].append(j)
... 
>>> 
>>> result
[['a', 'b', 'c'], ['a', 'b', 'c'], ['a', 'b', 'c']]
0 голосов
/ 07 октября 2010

Пожалуйста, включите runnable пример кода, чтобы мы могли выполнить код самостоятельно, чтобы быстро увидеть, что именно вы хотите сделать.Похоже, вы просто хотите это:

result = []
for i in range(x):
    data = []
    for j in someListOfElements:
        data.append(j)
    # or data = [j for j in someListOfElements]
    result.append(data)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...