2016-07-06 4 views
4

У меня есть список списков. Каждый подсписчик имеет длину от 1 до 100. Каждый подсписщик содержит идентификатор частицы в разное время в наборе данных. Я хотел бы сформировать списки всех идентификаторов частиц в данный момент времени. Для этого я мог бы использовать что-то вроде:Подрезки для резки различной длины

list = [[1,2,3,4,5],[2,6,7,8],[1,3,6,7,8]] 
    list2 = [item[0] for item in list] 

list2 будет содержать первые элементы каждого подсписка в списке. Я хотел бы сделать эту операцию не только для первого элемента, но и для каждого элемента от 1 до 100. Моя проблема заключается в том, что для каждого подсписок не существует элемента 100 (или 66 или 77 или любого другого).

Есть ли способ создания списков списков, где каждый подсписщик является списком всех идентификаторов частиц в данный момент времени.

Я думал о попытке использовать массивы numpy для решения этой проблемы, как если бы списки были одинаковой длины, это было бы тривиально. Я попытался добавить -1 в конец каждого списка, чтобы сделать их одинаковой длины, а затем маскировать отрицательные числа, но пока это не сработало. Я буду использовать список идентификаторов в данный момент времени, чтобы нарезать другой отдельный массив:

pos = pos[satIDs] 
+0

Вы хотите сделать это с помощью одной линии для цикла? или любой из циклов будет делать? – Navid777

+0

Любая петля будет делать, однако набор данных достаточно велик, поэтому скорость может быть проблемой. – Jack

+0

"маскировка отрицательных чисел, но это пока не сработало для меня" - Как это не сработало для вас? – Divakar

ответ

2
lst = [[1,2,3,4,5],[2,6,7,8],[1,3,6,7,8]] 
func = lambda x: [line[x] for line in lst if len(line) > x] 

func(3) 
[4, 8, 7] 
func(4) 
[5, 8] 

--update--

func = lambda x: [ (line[x],i) for i,line in enumerate(lst) if len(line) > x] 
func(4) 
[(5, 0), (8, 2)] 
+0

Отличное спасибо, есть ли способ отслеживать, какой элемент в func (x) пришел из какого списка, например. дополнительный список, в котором говорится, что (для func (4)), 5 пришли из подписок 0 и 8 пришли из подсписок 2? – Jack

+0

... в чем смысл использования 'lambda', а затем присвоения имени? Просто используйте 'def func (x): return [line [x] ...]'. – Bakuriu

+0

@Jack обновлен. первый элемент в tuple является значением, а второй - числом подписок – galaxyan

0

Если вы хотите с one-line forloop и в array вы можете сделать это:

list2 = [[item[i] for item in list if len(item) > i] for i in range(0, 100)] 

И если вы хотите знать, какой идентификатор из которого списка вы можете сделать это:

list2 = [{list.index(item): item[i] for item in list if len(item) > i} for i in range(0, 100)] 

песни2 бы так:

[{0: 1, 1: 2, 2: 1}, {0: 2, 1: 6, 2: 3}, {0: 3, 1: 7, 2: 6}, {0: 4, 1: 8, 2: 7}, 
{0: 5, 2: 8}, {}, {}, ... ] 
0

Вы можете добавить numpy.nan ваши короткие списки, а затем создать Numpy массив

import numpy 
import itertools 

lst = [[1,2,3,4,5],[2,6,7,8],[1,3,6,7,8,9]] 
arr = numpy.array(list(itertools.izip_longest(*lst, fillvalue=numpy.nan))) 

После этого вы можете использовать Numpy нарезку, как обычно.

print arr 
print arr[1, :] # [2, 6, 3] 
print arr[4, :] # [5, nan, 8] 
print arr[5, :] # [nan, nan, 9] 
+0

Если бы я сделал кусочек таким образом, мог бы я определить, из какой строки из каждого элемента в моем нарезанный массив? То есть будет ли он держать нанов? – Jack

+0

Да, конечно. всякий раз, когда вы запускаете конец любого из списков, эта запись становится «nan». –

+0

Но мог ли я использовать массив срезов, например x = [nan, nan, 9], чтобы выполнить срез другого массива, данные [x] - это не даст мне ошибку? IndexError: массивы, используемые в качестве индексов, должны быть целочисленными (или логическими) типами – Jack

0

Вы можете использовать itertools.zip_longest. Это будет zip списки вместе и вставьте None, когда один из списков исчерпан.

>>> lst = [[1,2,3,4,5],['A','B','C'],['a','b','c','d','e','f','g']]  
>>> list(itertools.zip_longest(*lst)) 
[(1, 'A', 'a'), 
(2, 'B', 'b'), 
(3, 'C', 'c'), 
(4, None, 'd'), 
(5, None, 'e'), 
(None, None, 'f'), 
(None, None, 'g')] 

Если вы не хотите None элементов, вы можете фильтровать их:

>>> [[x for x in sublist if x is not None] for sublist in itertools.zip_longest(*lst)] 
[[1, 'A', 'a'], [2, 'B', 'b'], [3, 'C', 'c'], [4, 'd'], [5, 'e'], ['f'], ['g']] 
0

Подход № 1

Один почти * Векторизованный подход можно предположить, что идет вдоль создание идентификатора на основе нового порядка и расщепления, например:

def position_based_slice(L): 

    # Get lengths of each element in input list 
    lens = np.array([len(item) for item in L]) 

    # Form ID array that has *ramping* IDs within an element starting from 0 
    # and restarts with a new element at 0 
    id_arr = np.ones(lens.sum(),int) 
    id_arr[lens[:-1].cumsum()] = -lens[:-1]+1 

    # Get order maintained sorted indices for sorting flattened version of list 
    ids = np.argsort(id_arr.cumsum(),kind='mergesort') 

    # Get sorted version and split at boundaries decided by lengths of ids 
    vals = np.take(np.concatenate(L),ids) 
    cut_idx = np.where(np.diff(ids)<0)[0]+1 
    return np.split(vals,cut_idx) 

* В начале есть понимание цикла, но для того, чтобы собирать только длины входных элементов списка, его влияние на общую продолжительность выполнения должно быть минимальным.

Пример запуск -

In [76]: input_list = [[1,2,3,4,5],[2,6,7,8],[1,3,6,7,8],[3,2]] 

In [77]: position_based_slice(input_list) 
Out[77]: 
[array([1, 2, 1, 3]), # input_list[ID=0] 
array([2, 6, 3, 2]), # input_list[ID=1] 
array([3, 7, 6]), # input_list[ID=2] 
array([4, 8, 7]), # input_list[ID=3] 
array([5, 8])]  # input_list[ID=4] 

Подход № 2

Вот еще один подход, который создает 2D массива, который легче индексировать и проследить обратно исходные входные элементы. Это использует вещание NumPy наряду с булевым индексированием. Реализация будет выглядеть примерно так -

def position_based_slice_2Dgrid(L): 

    # Get lengths of each element in input list 
    lens = np.array([len(item) for item in L]) 

    # Create a mask of valid places in a 2D grid mapped version of list 
    mask = lens[:,None] > np.arange(lens.max()) 
    out = np.full(mask.shape,-1,dtype=int) 
    out[mask] = np.concatenate(L) 
    return out 

Пример запуск -

In [126]: input_list = [[1,2,3,4,5],[2,6,7,8],[1,3,6,7,8],[3,2]] 

In [127]: position_based_slice_2Dgrid(input_list) 
Out[127]: 
array([[ 1, 2, 3, 4, 5], 
     [ 2, 6, 7, 8, -1], 
     [ 1, 3, 6, 7, 8], 
     [ 3, 2, -1, -1, -1]]) 

Итак, теперь каждый столбец вывода будет соответствовать вашему удостоверению на основе вывода.

Смежные вопросы