#python #list #numpy #vectorization #numpy-ndarray
#python #Список #numpy #векторизация #numpy-ndarray
Вопрос:
l = [2,4,6,12,14,16,21,27,29,31]
Я хочу разделить его на списки, чтобы элементы каждого списка представляли собой монотонный список с разницей в 2 между элементами:
new_l = [[2,4,6], [12,14,16],[21], [27,29,31]]
Каков наиболее эффективный способ сделать это?
Ответ №1:
Обновить
Можно вообще избежать циклов Python и использовать только comprehensions
(вместе с zip
) для некоторого повышения эффективности. Вы можете сделать это следующим образом:
l = [2,4,6,12,14,16,21,27,29,31, 44]
n = len(l)
#Find the splitting points (where the monotonic condition breaks):
splitting_points = [0] [k for k in range(1, n) if l[k] - l[k - 1] != 2]
if splitting_points[-1] != n:
splitting_points.append(n)
#Then split the list into intervals having bounds in the splitting_points:
new_l = [l[i: j] for i, j in zip(splitting_points[:-1], splitting_points[1:])]
print(new_l)
Это «должно» быть намного быстрее, чем циклы (особенно для больших списков), но я не проводил никаких сравнительных тестов.
Оригинал
Вы должны перебирать начальный список l
, поддерживать текущий список с текущей монотонной последовательностью, и всякий раз, когда новый повторяющийся элемент нарушает монотонное условие, вставляйте текущий список и очищайте его.
Вот код, который делает именно это:
l = [2,4,6,12,14,16,21,27,29,31]
new_l = []
current_l = [l[0]] #initially, insert the first element
for k in range(1, len(l)):
if l[k] - current_l[-1] == 2: #if the monotonic condition is satisfied
current_l.append(l[k]) #we append the element
else:
new_l.append(current_l) #otherwise, we append the previous list to the answer
current_l = [l[k]] #and clear the running sequence
new_l.append(current_l) #there will always be a last sequence not appended to the answer
print(new_l)
Комментарии:
1. нет ли более эффективного способа для этого?
2. С точки зрения сложности это наиболее эффективный способ, потому что вам нужно выполнить итерацию по списку хотя бы один раз. Однако циклы for в Python не очень эффективны. Я не думаю, что есть другой способ использовать понимания или что-то в этом роде, потому что это своего рода конкретная проблема, с которой вы столкнулись здесь :/
Ответ №2:
Вы можете определить индексы, которые нужно разделить, а затем применить np.split
следующим образом:
np.split(l, np.flatnonzero(np.diff(l)!=2) 1)
Вывод:
[array([2, 4, 6]), array([12, 14, 16]), array([21]), array([27, 29, 31])]
Однако игра с массивами разной длины никогда не бывает эффективной, поэтому np.split
она довольно медленная.