Создание списка отдельных элементов списка, умноженных n раз
Я довольно новичок в Python и думаю, что это должна быть довольно распространенная проблема, но не может найти решение. Я уже просмотрел эту страницу и нашел ее полезной для одного элемента, но я изо всех сил пытаюсь расширить пример до нескольких элементов, не используя цикл «для». Я запускаю этот бит кода для 250 ходоков через Emcee, поэтому я ищу самый быстрый способ.
У меня есть список чисел, a = [x,y,z]
которые я хочу повторить b = [1,2,3]
раза (например), поэтому я заканчиваю списком списков:
[ [x], [y,y], [z,z,z] ]
Для цикла «for» у меня есть:
c = [ ] for i in range (0,len(a)): c.append([a[i]]*b[i])
Что делает именно то, что я хочу, но означает, что мой код мучительно медленный. Я также попытался наивно превращать a и b в массивы и делать [a]*b
в надежде, что он будет умножать элемент за элементом, но без радости.
- Используя маску массива bool, замените False значения на NaN
- Проблема с кодом Python 3
- Преобразование байтового массива в отдельные биты в массиве
- Почему функция numpy fortyter требует указания dtype, если нет других процедур создания массивов?
- Как вернуть массив C в Python?
Вы можете использовать zip
и список:
>>> a = ['x','y','z'] >>> b = [1,2,3] >>> [[x]*y for x,y in zip(a,b)] [['x'], ['y', 'y'], ['z', 'z', 'z']]
или:
>>> [[x for _ in xrange(y)] for x,y in zip(a,b)] [['x'], ['y', 'y'], ['z', 'z', 'z']]
zip
сначала создаст весь список в памяти, чтобы использовать итератор itertools.izip
Если a
содержит измененные объекты, такие как списки или списки списков, тогда вам, возможно, придется использовать copy.deepcopy
здесь, потому что изменение одной копии также изменит другие копии:
>>> from copy import deepcopy as dc >>> a = [[1 ,4],[2, 5],[3, 6, 9]] >>> f = [[dc(x) for _ in xrange(y)] for x,y in zip(a,b)] #now all objects are unique >>> [[id(z) for z in x] for x in f] [[172880236], [172880268, 172880364], [172880332, 172880492, 172880428]]
сравнение времени (игнорирование импорта):
>>> a = ['x','y','z']*10**4 >>> b = [100,200,300]*10**4 >>> %timeit [[x]*y for x,y in zip(a,b)] 1 loops, best of 3: 104 ms per loop >>> %timeit [[x]*y for x,y in izip(a,b)] 1 loops, best of 3: 98.8 ms per loop >>> %timeit map(lambda v: [v[0]]*v[1], zip(a,b)) 1 loops, best of 3: 114 ms per loop >>> %timeit map(list, map(repeat, a, b)) 1 loops, best of 3: 192 ms per loop >>> %timeit map(list, imap(repeat, a, b)) 1 loops, best of 3: 211 ms per loop >>> %timeit map(mul, [[x] for x in a], b) 1 loops, best of 3: 107 ms per loop >>> %timeit [[x for _ in xrange(y)] for x,y in zip(a,b)] 1 loops, best of 3: 645 ms per loop >>> %timeit [[x for _ in xrange(y)] for x,y in izip(a,b)] 1 loops, best of 3: 680 ms per loop
Самый быстрый способ сделать это с помощью map () и operator.mul () :
>>> from operator import mul >>> map(mul, [['x'], ['y'], ['z']], [1, 2, 3]) [['x'], ['y', 'y'], ['z', 'z', 'z']]
>>> from itertools import repeat >>> from itertools import starmap >>> a = ['x','y','z'] >>> b = [1,2,3] >>> starmap(repeat,zip(a,b))
starmap
возвращает итерабельность, которая содержит значения, равные результату вызова repeat
с аргументами, равными значениям, содержащимся в кортеже, в данном случае, например, ('x',1)
.
>>> for p in starmap(repeat,zip(a,b)): print(list(p)) ['x'] ['y', 'y'] ['z', 'z', 'z']
@kirelagin предложил версию без циклов, вот тот, который также не имеет lambda
(помните, что решение от @AshwiniChaudhary наиболее читаемо)
>>> from itertools import repeat >>> a = ['x','y','z'] >>> b = [1,2,3] >>> map(list, map(repeat, a, b)) [['x'], ['y', 'y'], ['z', 'z', 'z']]
>>> map(repeat, a, b) [repeat('x', 1), repeat('y', 2), repeat('z', 3)]
создает список repeat
объектов (используйте imap
на Python 2.x, если вы хотите использовать ленивый итератор вместо списка), которые не занимают лишнего места в памяти, это здорово, если вы просто хотите перебирать элементы вместо их хранить)
Вот версия без циклов, если вам почему-то не нравятся:
map(lambda v: [v[0]]*v[1], zip(a,b))
Я также должен предупредить вас, что эта версия немного медленнее, чем понимание списка:
$ a = ['hi']*100 $ b = [20]*100 $ %timeit map(lambda v: [v[0]]*v[1], zip(a,b)) 10000 loops, best of 3: 101 us per loop %timeit [[x]*y for x,y in zip(a,b)] 10000 loops, best of 3: 74.1 us per loop
Я бы также рекомендовал использовать itertools.izip
вместо zip
если вы на Python 2.
- Замените NaN в массиве NumPy с ближайшим значением, отличным от NaN
- ошибка с добавлением к файлу и использование массива
- Cython beginner – ускорение бесчисленного вещания
- Разрыв столбца с массивом массивов – PySpark
- Numpy Arrays: Извлечение предпочтительных упорядоченных значений из массива с Nans без заполнения?
- Улучшение использования памяти в массиве, чтобы избежать блочной обработки
- Построение графика по осям, но получение результатов при попытке классифицировать изображение на основе функций HoG
- Как найти пики в массиве 1d
- Как рассчитать долю каждой ячейки в матрице до суммы столбца?