2013-11-27 2 views
2

Учитывая такую ​​проблему, что является наиболее эффективным (или достаточно эффективным) способом сделать это в Python:раскалывается Списки Списки по длине в Python

проблемы. Учитывая список списков,

L = [list_0, list_1, list_2, list_3, ..., list_n] 

где LEN (list_i) < = 3, скажем, для каждого списка внутри L. Как мы можем разделить L в L_1, L_2, L_3, где L_1 имеет только длина 1, L_2 имеет только 2 списка, а L_3 имеет только 3 списка?

Потенциальные решения. Вот лучшее, что я мог сделать; Я также включил образец здесь. Он работает примерно на 8,6 секунды на моем ПК.

import time 

# These 4 lines make a large sample list-of-list to test on. 
asc_sample0 = [[i] for i in range(500)] 
asc_sample1 = [[i,j] for i in range(500) for j in range(20)] 
asc_sample2 = [[i,j,k] for i in range(20) for j in range(10) for k in range(20)] 
asc_sample = asc_sample0 + asc_sample1 + asc_sample2 

start = time.clock() 
cells0 = [i for i in asc if len(i) == 1] 
cells1 = [i for i in asc if len(i) == 2] 
cells2 = [i for i in asc if len(i) == 3] 
print time.clock() - start 

Я также попытался «вынуть» элементы и добавить в списки cell0 и т. Д., Но это заняло значительно больше времени. Я также попытался добавить, а затем удалить этот элемент, чтобы я мог пройти через один цикл, который работал нормально, когда были, скажем, 10^10 списков размера 1, но только несколько из 2 и 3 размеров, но, в общем, это было неэффективно.

В основном я ценю некоторые сообразительные идеи. Я знаю, что один из ответов, скорее всего, будет «Напиши это на С», но пока я просто хотел бы посмотреть на решения Python для этого.

+0

Что точка 'L_3'? Вы только что сказали «len (list_i) <= 2' для всех списков в L. – slider

+0

Возможно, вы можете получить значительное ускорение, сортируя список, а затем используя' itertools.groupby' –

+0

@slider Извините; Я имел в виду, что это будет 3. Это немного запутанно, потому что в списках длины 1 обозначаются «0-ячейки», длина 1 указывает на «1-клетки» и т. Д., Поэтому я смешиваю пучок. Отредактировано, чтобы отразить это! – james

ответ

2

Это, безусловно, один из лучших, потому что он работает параллельно. Еще одна вещь, на которую вы должны обратить внимание, - это itertools.groupby и встроенный метод filter.

+0

Itertools.groupby выглядит хорошо; Я попробую это. Для метода фильтра документ для 2.7.x говорит, что это эквивалентно рассмотрению списка выше, если только я не думаю об этом неправильно. – james

+0

Метод 'filter' создает генератор * в python 3.x, который имеет ряд преимуществ перед пониманием списка. – randomusername

+0

Если вы хотите использовать groupby, вам нужно сначала отсортировать по длине –

3

старомодное решение могло бы работать лучше здесь:

cells0, cells1, cells2 = [], [], [] 

for lst in asc_sample: 
    n = len(lst) 
    if n == 1: 
     cells0.append(lst) 
    elif n == 2: 
     cells1.append(lst) 
    else: 
     cells2.append(lst) 
+3

Точно. Одна итерация вместо трех. – slider

+1

Я использовал 'cells_by_length = collections.defaultdict (list)', чтобы сократить код для внутреннего цикла на 'sublist в asc_sample: cells_by_length [len (sublist)]. Append (sublist)', но это та же идея. –

+0

Это работает медленнее, чем оригинал на моем компьютере! –

2
result = dict() 

for lst in L: 
    result.setdefault(len(lst), []).append(lst) 

print result 

Выход

{ 
1: [[0], [1], [2], [3]], 
2: [[0, 0], [0, 1], [0, 2]], 
3: [[0, 0, 0], [0, 0, 1], [0, 0, 2]] 
} 
+0

Это работает немного медленнее, чем остальные, но не намного! Однако я не знал о setdefault, что довольно круто. – james

2

Индексация список/кортеж должен быть быстрее, чем делать ключевые поиск. Это около 30% быстрее, чем версия данного в вопросе

cells = [],[],[],[]  # first list here isn't used, but it's handy for the second version 
for i in asc: 
    cells[len(i)].append(i) 

Чуть быстрее снова извлекая методы добавления (На больших списках это почти в два раза быстрее, чем ОП)

cells = [],[],[],[] 
appends = [x.append for x in cells] 
for i in asc: 
    appends[len(i)](i) 
+0

Для меня первый, кажется, работает немного медленнее на очень, очень больших списках, но второй немного быстрее оригинала. Второй - тоже аккуратный, потому что я понятия не имел, что вы можете так поступить - или, по крайней мере, я не думаю, что раньше видел такие вещи. – james

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