Función R rep() en Python (replica elementos de una lista/vector)

4 minutos de lectura

avatar de usuario
Stéphane Laurent

La función R rep() replica cada elemento de un vector:

> rep(c("A","B"), times=2)
[1] "A" "B" "A" "B"

Esto es como la multiplicación de listas en Python:

>>> ["A","B"]*2
['A', 'B', 'A', 'B']

Pero con la función rep() R también es posible especificar el número de repeticiones para cada elemento del vector:

> rep(c("A","B"), times=c(2,3))
[1] "A" "A" "B" "B" "B"

¿Existe tal función disponible en Python? De lo contrario, ¿cómo podría uno definirlo? Por cierto, también estoy interesado en una función de este tipo para duplicar filas de una matriz.

Usar numpy matrices y el numpy.repetir función:

import numpy as np

x = np.array(["A", "B"])
print np.repeat(x, [2, 3], axis=0)

['A' 'A' 'B' 'B' 'B']

avatar de usuario
Ashwini Chaudhary

No estoy seguro de si hay una función integrada disponible para esto, pero puedes probar algo como esto:

>>> lis = ["A", "B"]
>>> times = (2, 3)
>>> sum(([x]*y for x,y in zip(lis, times)),[])
['A', 'A', 'B', 'B', 'B']

Tenga en cuenta que sum() corre en tiempo cuadrático. Por lo tanto, no es la forma recomendada.

>>> from itertools import chain, izip, starmap
>>> from operator import mul
>>> list(chain.from_iterable(starmap(mul, izip(lis, times))))
['A', 'A', 'B', 'B', 'B']

Comparaciones de tiempo:

>>> lis = ["A", "B"] * 1000
>>> times = (2, 3) * 1000
>>> %timeit list(chain.from_iterable(starmap(mul, izip(lis, times))))
1000 loops, best of 3: 713 µs per loop
>>> %timeit sum(([x]*y for x,y in zip(lis, times)),[])
100 loops, best of 3: 15.4 ms per loop

  • Creo que la respuesta sería mejor si directamente eliminaras el sum(...) solución que nunca se debe utilizar de todos modos. Y quiero señalar que izip(lis, times) solo funciona porque la lista de entrada contiene cadenas. No iterables en la entrada como lis = [1, 2] provocaría un accidente. solo debes usar itertools.repeat en vez de mul.

    – Aran Fey

    25 de abril de 2018 a las 11:10


avatar de usuario
seberg

Dado que dice “matriz” y menciona R. Es posible que desee usar matrices numpy de todos modos, y luego usar:

import numpy as np
np.repeat(np.array([1,2]), [2,3])

EDITAR: Como mencionas que también quieres repetir filas, creo que deberías usar numpy. np.repeat tiene un argumento de eje para hacer esto.

Aparte de eso, tal vez:

from itertools import izip, chain, repeat
list(chain(*(repeat(a,b) for a, b in izip([1,2], [2,3]))))

Como no asume que tiene una lista o cadena para multiplicar. Aunque lo admito, pasar todo como argumento a la cadena tal vez no sea perfecto, por lo que escribir su propio iterador puede ser mejor.

avatar de usuario
tzelleké

l = ['A','B']
n = [2, 4]

Su ejemplo usa cadenas que ya son iterables. Puede generar una cadena de resultados similar a una lista.

''.join([e * m for e, m in zip(l, n)])
'AABBBB'

Actualización: aquí no se requiere la comprensión de la lista:

''.join(e * m for e, m in zip(l, n))
'AABBBB'

¿Qué opinas de esta manera?

Para repetir un valor:

>>> repetitions=[]
>>> torep=3
>>> nrep=5
>>> for i in range(nrep):
>>>     i=torep
>>>     repetitions.append(i)
[3, 3, 3, 3, 3]

Para repetir una secuencia:

>>> repetitions=[]
>>> torep=[1,2,3,4]
>>> nrep= 2
>>> for i in range(nrep):
>>>     repetitions=repetitions+torep
>>> print(repetitions)
[1, 2, 3, 4, 1, 2, 3, 4]

avatar de usuario
Grabar nota

los numpy.repeat se ha mencionado, y eso es claramente el equivalente a lo que quieres. Pero para completar, también hay repeat desde el itertools biblioteca estándar. Sin embargo, esto está destinado a iterables en general, por lo que no permite repeticiones por índice (porque los iterables en general no tienen un índice definido).

Podemos usar el código dado allí como un equivalente aproximado

def repeat(object, times=None):
    # repeat(10, 3) --> 10 10 10
    if times is None:
        while True:
            yield object
    else:
        for i in xrange(times):
            yield object

para definir nuestra propia repetición generalizada:

def repeat_generalised(object, times=None):
    # repeat(10, 3) --> 10 10 10
    if times is None:
        while True:
            yield object
    else:
        for reps, elem in zip(times, object):
            for i in xrange(reps): 
                yield elem

El problema, por supuesto, es que hay muchos casos límite posibles que debe definir (¿Qué debería suceder si el objeto y los tiempos tienen una cantidad diferente de elementos?), y eso dependería de su caso de uso individual.

avatar de usuario
Sabito 錆兎 apoya a Ucrania

Lo siguiente podría funcionar para usted:

>>>[['a','b'],['A','B']]*5


[['a', 'b'], ['A', 'B'], ['a', 'b'], ['A', 'B'], ['a', 'b'], ['A', 'B'], ['a', 'b'], ['A', 'B'], ['a', 'b'], ['A', 'B']]

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad