Python: создайте массив, используя значения и индексы заданного массива

#python #python-3.x #list #numpy

#python #python-3.x #Список #numpy

Вопрос:

Учитывая следующий список (или массив numpy):

 x = [4, 3, 1, 2]
  

Я хочу сгенерировать другой список (или массив numpy) с 1 4 3 2 =10 элементов, таких как:

 y = [1, 1, 1, 1, 2, 2, 2, 3, 4, 4]
  

Где y будут иметь x[i] последовательные элементы со значением i .

Другие примеры:

 x = [0,3,1]
y = [2,2,2,3]

x = [2,0,2]
y = [1,1,3,3]

x = [1,1,1,1,1]
y = [1,2,3,4,5]
  

Как это можно сделать эффективно? Большое спасибо.

Комментарии:

1. Добро пожаловать. Было бы здорово, если бы вы могли также включить написанный вами код.

Ответ №1:

Это делает работу:

 x = [4,3,1,2]

y = []
for index, num in enumerate(x):
    for i in range(num):
        y.append(index   1)
        
print(y)
  

или, если вы предпочитаете, с пониманием списка в одной строке:

 x = [4,3,1,2]

y = [index   1 for index, num in enumerate(x) for i in range(num)]
        
print(y)
  

Вывод:

 [1, 1, 1, 1, 2, 2, 2, 3, 4, 4]
  

Комментарии:

1. @Burak Отлично! Если бы вы могли пометить ответ как решатель, было бы здорово

2. @LorenzoZane другим вариантом было бы enumerate(x, start=1)

3. @LorenzoZane Кстати, я нашел второе решение наиболее экономичным в чистом Python. numpy это другая категория ( np.repeat производительность> 20x для большого набора данных).

Ответ №2:

Если вы хотите использовать numpy :

 x = np.array([4, 3, 1, 2])
a = np.arange(1, x.size 1)

np.repeat(a, x)
  

Вывод:

 array([1, 1, 1, 1, 2, 2, 2, 3, 4, 4])
  

Комментарии:

1. Почему np.repeat(a, [*x]) вместо np.repeat(a, x) ?

2. @mathfux — Спасибо, это было излишним. По какой-то причине, когда я изначально писал его, этот метод не работал, но теперь все в порядке. Должно быть, я сделал что-то глупое. Отредактировано — спасибо.

Ответ №3:

Излишне сложный способ сделать это заключается в следующем, используя понимание списка и reduce функцию:

 from functools import reduce

def f(ls):
    return reduce(lambda x, y: x y, [[i 1]*ls[i] for i in range(len(ls))])

>>> f([0, 3, 1])
[2, 2, 2, 3]
>>> f([2, 0, 2])
[1, 1, 3, 3]
>>> f([1, 1, 1, 1, 1])
[1, 2, 3, 4, 5]
  

Комментарии:

1. Это блестяще, но это требует производительности. Это в 8 раз медленнее, чем самое быстрое решение на чистом Python.

Ответ №4:

 In [52]: alist, reps = [1,2,3,4], [4,3,1,2]
  

np.repeat делает ли такое повторение приятным — но это делает вещи массивами (что требует времени):

 In [53]: np.repeat(alist,reps)
Out[53]: array([1, 1, 1, 1, 2, 2, 2, 3, 4, 4])
  

Повтор списка может использоваться с:

 In [54]: [[i]*j for i,j in zip([1,2,3,4],[4,3,1,2])]
Out[54]: [[1, 1, 1, 1], [2, 2, 2], [3], [4, 4]]
  

и списки списков могут быть сглажены с помощью:

 In [55]: [k for l in ([i]*j for i,j in zip(alist, reps)) for k in l]
Out[55]: [1, 1, 1, 1, 2, 2, 2, 3, 4, 4]
In [56]: list(itertools.chain(*([i]*j for i,j in zip(alist, reps))))
Out[56]: [1, 1, 1, 1, 2, 2, 2, 3, 4, 4]
  

Некоторые тайминги:

 In [57]: timeit np.repeat(alist,reps)
10.9 µs ± 398 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
  

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

 In [58]: %%timeit a,b = np.array(alist), np.array(reps)
    ...:  np.repeat(a,b)
    ...: 
2.97 µs ± 103 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
  

Но для этого небольшого примера методы list работают быстрее:

 In [59]: timeit [k for l in ([i]*j for i,j in zip(alist, reps)) for k in l]
2.33 µs ± 70.4 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [60]: timeit list(itertools.chain(*([i]*j for i,j in zip(alist, reps))))
2.46 µs ± 76.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
  

Для больших случаев я ожидаю, что [58] раз будут масштабироваться наилучшим образом. Я не уверен насчет других.