Получаване на индексите на всички елементи, които не са None, от подсписък в Python?

Според заглавието, имам вложени списъци така (вложеният списък е с фиксирана дължина):

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

Бих искал да върна списък (броят елементи, равен на дължината на подсписък от list1), където подсписъците са индексите на редове без None като техен X-ти елемент, т.е.:

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

... което работи, но може да е бавно (дължините на списъците са стотици хиляди).

Има ли по-добър/по-ефективен начин да направите това?

РЕДАКТИРАНЕ:

Преработих горните for цикли в разбирания на вложени списъци (подобно на отговора на SilentGhost). Следващият ред дава същия резултат като моята оригинална реализация, но работи приблизително 10 пъти по-бързо.

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

person Noah    schedule 05.05.2010    source източник
comment
вашият редактиран вариант е невалиден, тъй като list1[i] винаги не е None, например list1[0] е [1, "foo", 10] (забележка: [None, None, None] is not None).   -  person jfs    schedule 05.05.2010
comment
Благодаря - мисля, че вече го оправих.   -  person Noah    schedule 06.05.2010


Отговори (3)


>>> [[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, за да избегнете генерирането на междинен списък.

person SilentGhost    schedule 05.05.2010

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

Горното изглежда е около 10 пъти по-бързо от първоначалния ми пост.

person Noah    schedule 05.05.2010

person    schedule
comment
този вариант е 3 пъти по-бавен от този на @SilentGhost (на някакъв вход). - person jfs; 05.05.2010