Получить индексы всех не-None элементов из подсписка в Python? - PullRequest
2 голосов
/ 05 мая 2010

В соответствии с заголовком, у меня есть вложенные списки, такие как (вложенный список имеет фиксированную длину):

        # ID,  Name, Value
list1 = [[ 1, "foo",    10],
         [ 2, "bar",  None],
         [ 3, "fizz",   57],
         [ 4, "buzz", None]]

Я бы хотел вернуть список (количество элементов, равное длине подсписка от list1), где подсписки - это индексы строк, в которых X-ным элементом не является None, т.е.

[[non-None ID indices], [non-None Name indices], [non-None Value indices]]

Используя list1 в качестве примера, результат должен быть:

[[0, 1, 2, 3], [0, 1, 2, 3], [0, 2]]

Моя текущая реализация:

indices = [[] for _ in range(len(list1[0]))]
for i, row in enumerate(list1):
    for j in range(len(row)):
        if not isinstance(row[j], types.NoneType):
            indices[j].append(i)

... который работает, но может быть медленным (длина списков исчисляется сотнями тысяч).

Есть ли лучший / более эффективный способ сделать это?

EDIT:

Я реорганизовал вышеприведенные циклы для понимания вложенного списка (аналогично ответу SilentGhost). Следующая строка дает тот же результат, что и моя оригинальная реализация, но работает примерно в 10 раз быстрее.

[[i for i in range(len(list1)) if list1[i][j] is not None] for j in range(len(log[0]))]

Ответы [ 3 ]

6 голосов
/ 05 мая 2010
>>> [[i for i, j in enumerate(c) if j is not None] for c in zip(*list1)]
[[0, 1, 2, 3], [0, 1, 2, 3], [0, 2]]

в python-2.x вы можете использовать itertools.izip вместо zip, чтобы избежать создания промежуточного списка.

1 голос
/ 05 мая 2010
[[i for i in range(len(list1)) if list1[i] is not None] for _ in range(len(log[0]))]

Выше, кажется, примерно в 10 раз быстрее, чем мой оригинальный пост.

0 голосов
/ 05 мая 2010
import numpy as np

map(lambda a: np.not_equal(a, None).nonzero()[0], np.transpose(list1))
# -> [array([0, 1, 2, 3]), array([0, 1, 2, 3]), array([0, 2])]
...