R-functie rep() in Python (repliceert elementen van een lijst/vector)

De R-functie rep() repliceert elk element van een vector:

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

Dit is zoals de lijstvermenigvuldiging in Python:

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

Maar met de rep() R-functie is het ook mogelijk om het aantal herhalingen voor elk element van de vector te specificeren:

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

Is er zo’n functie beschikbaar in Python? Hoe zou men het anders kunnen definiëren? Ik ben trouwens ook geïnteresseerd in zo’n functie voor het dupliceren van rijen van een array.


Antwoord 1, autoriteit 100%

Gebruik numpyarrays en de numpy.repeatfunctie:

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

Antwoord 2, autoriteit 14%

Ik weet niet zeker of hier een ingebouwde functie voor beschikbaar is, maar je kunt zoiets als dit proberen:

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

Merk op dat sum()in kwadratische tijd wordt uitgevoerd. Het is dus niet de aanbevolen manier.

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

Tijdvergelijkingen:

>>> 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

Antwoord 3, autoriteit 7%

Omdat je “array” zegt en R noemt. Misschien wil je toch numpy arrays gebruiken en dan gebruiken:

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

EDIT: aangezien je zegt dat je ook rijen wilt herhalen, denk ik dat je numpy moet gebruiken. np.repeatheeft een asargument om dit te doen.

Anders dan dat, misschien:

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

Omdat het er niet vanuit gaat dat je een lijst of string hebt om te vermenigvuldigen. Hoewel ik toegeef dat het misschien niet perfect is om alles als argument in een keten door te geven, dus het is misschien beter om je eigen iterator te schrijven.


Antwoord 4, autoriteit 4%

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

Uw voorbeeld gebruikt strings die al iterables zijn.
U kunt een resultaatreeks produceren die lijkt op een lijst.

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

Update: het begrip van de lijst is hier niet vereist:

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

Antwoord 5, autoriteit 4%

Wat vind je van deze manier?

Een waarde herhalen:

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

Een reeks herhalen:

>>> 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]

Antwoord 6

De numpy.repeatis genoemd, en dat is duidelijk het equivalent van wat je wilt. Maar voor de volledigheid is er ook repeatuit de itertoolsstandaardbibliotheek. Dit is echter bedoeld voor iterables in het algemeen, dus herhalingen per index zijn niet toegestaan ​​(omdat iterables in het algemeen geen index hebben).

We kunnen de code die daar wordt gegeven als een ruw equivalent gebruiken

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

om onze eigen algemene herhaling te definiëren:

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

Het probleem is natuurlijk dat er veel mogelijke randgevallen zijn die je moet definiëren (wat zou er moeten gebeuren als object en tijden een ander aantal elementen hebben?) en dat hangt af van je individuele gebruiksgeval.

>


Antwoord 7

Het volgende kan voor u werken:

>>>[['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']]

Antwoord 8

Hier is mijn poging tot een kloon van Rrep:

def rep(x, times = 1, each = 1, length_out = None):
    if not isinstance(times, list):
        times = [times]
    res = ''.join([str(i) * each for i in x])
    if len(times) > 1:   
        res = ''.join(str(i) * m for i, m in zip(x, times))
    else:
        res = ''.join(res * times[0])
    if length_out is None:
        return res
    else:
        return res[0:length_out]

Reproduceert de Rvoorbeelden:

rep(range(4), times = 2)
rep(range(4), each = 2)
rep(range(4), times = [2,2,2,2])
rep(range(4), each = 2, length_out = 4)
rep(range(4), each = 2, times = 3)

behalve dat er geen hergebruik van kortere vectoren/lijsten is (imo is dit de slechtsteeigenschap van R).

Other episodes