La fonction range permet-elle la concaténation? Comme je veux faire une range(30)
& concaténer avec range(2000, 5002)
. Donc, ma gamme concaténée sera 0, 1, 2, ... 29, 2000, 2001, ... 5001
Un code comme celui-ci ne fonctionne pas sur mon dernier python (ver: 3.3.0)
range(30) + range(2000, 5002)
Vous pouvez utiliser itertools.chain
pour cela:
from itertools import chain
concatenated = chain(range(30), range(2000, 5002))
for i in concatenated:
...
Cela fonctionne pour les iterables arbitraires. Notez qu'il existe une différence de comportement entre range()
entre Python 2 et 3 que vous devriez connaître: en Python 2 range
renvoie une liste, et en Python3 un itérateur, efficace en termes de mémoire, toujours souhaitable.
Les listes peuvent être concaténées avec +
, les itérateurs ne le peuvent pas.
Peut être fait en utilisant list-comprehension .
>>> [i for j in (range(10), range(15, 20)) for i in j]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 15, 16, 17, 18, 19]
Cela fonctionne pour votre demande, mais la réponse est longue et je ne l’afficherai pas ici.
remarque: peut être transformé en générateur pour des performances accrues:
for x in (i for j in (range(30), range(2000, 5002)) for i in j):
# code
ou même dans une variable génératrice.
gen = (i for j in (range(30), range(2000, 5002)) for i in j)
for x in gen:
# code
J'aime les solutions les plus simples possibles (y compris l'efficacité). On ne sait pas toujours si la solution est telle. Quoi qu'il en soit, la range()
de Python 3 est un générateur. Vous pouvez l'envelopper à n'importe quelle construction qui effectue l'itération. La list()
est capable de construire une valeur de liste à partir de n'importe quelle valeur itérable. L'opérateur +
pour les listes effectue la concaténation. J'utilise des valeurs plus petites dans l'exemple:
>>> list(range(5))
[0, 1, 2, 3, 4]
>>> list(range(10, 20))
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
>>> list(range(5)) + list(range(10,20))
[0, 1, 2, 3, 4, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
C’est ce que range(5) + range(10, 20)
a fait exactement dans Python 2.5 - car range()
a renvoyé une liste.
En Python 3, cela n’est utile que si vous voulez vraiment construire la liste. Sinon, je recommande la solution Lev Levitsky avec itertools.chain . La documentation montre également la mise en œuvre très simple:
def chain(*iterables):
# chain('ABC', 'DEF') --> A B C D E F
for it in iterables:
for element in it:
yield element
La solution de Inbar Rose est correcte et fonctionnellement équivalente. Quoi qu'il en soit, mon +1 va à Lev Levitsky et à son argumentation sur l'utilisation des bibliothèques standard. De Le zen de Python ...
Face à l'ambiguïté, refusez la tentation de deviner.
#!python3
import timeit
number = 10000
t = timeit.timeit('''\
for i in itertools.chain(range(30), range(2000, 5002)):
pass
''',
'import itertools', number=number)
print('itertools:', t/number * 1000000, 'microsec/one execution')
t = timeit.timeit('''\
for x in (i for j in (range(30), range(2000, 5002)) for i in j):
pass
''', number=number)
print('generator expression:', t/number * 1000000, 'microsec/one execution')
À mon avis, le itertools.chain
est plus lisible. Mais ce qui est vraiment important ...
itertools: 264.4522138986938 microsec/one execution
generator expression: 785.3081048010291 microsec/one execution
... c'est environ 3 fois plus vite.
Avec l'aide de la méthode extend, nous pouvons concaténer deux listes.
>>> a = list(range(1,10))
>>> a.extend(range(100,105))
>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9, 100, 101, 102, 103, 104]
Sur python3.5 +, vous pouvez utiliser le décompactage itérable dans les listes (voir PEP 448: Généralisations de décompression supplémentaires ).
Si vous avez besoin d'une liste,
[*range(2, 5), *range(3, 7)]
# [2, 3, 4, 3, 4, 5, 6]
Cela préserve l’ordre et ne supprime pas les doublons. Ou, vous voudrez peut-être un tuple,
(*range(2, 5), *range(3, 7))
# (2, 3, 4, 3, 4, 5, 6)
... ou un ensemble,
{*range(2, 5), *range(3, 7)}
# {2, 3, 4, 5, 6}
Il se trouve également que cela est plus rapide que d’appeler chain
.
%timeit list(chain(range(10000), range(5000, 20000)))
%timeit [*range(10000), *range(5000, 20000)]
738 µs ± 10.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
665 µs ± 13.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
L’avantage de chain
, cependant, est que vous pouvez passer une liste arbitraire de plages.
r = [range(2, 5), range(3, 7), ...]
flat = list(chain.from_iterable(r))
OTOH, les généralisations de décompression n'ont pas été généralisées à des séquences arbitraires, vous devrez donc décompresser vous-même les plages individuelles.
range()
dans Python 2.x renvoie une liste:
>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
xrange()
dans Python 2.x renvoie un itérateur:
>>> xrange(10)
xrange(10)
Et en Python 3, range()
renvoie également un itérateur:
>>> r = range(10)
>>> iterator = r.__iter__()
>>> iterator.__next__()
0
>>> iterator.__next__()
1
>>> iterator.__next__()
2
Il est donc clair que vous ne pouvez pas concaténer des itérateurs autres en utilisant chain()
comme l’a dit l’autre personne.
Je suis venu à cette question parce que j'essayais de concaténer un nombre inconnu de plages, qui pourraient se chevaucher, et je ne voulais pas de valeurs répétées dans l'itérateur final. Ma solution a été d'utiliser set
et l'opérateur union
comme suit:
range1 = range(1,4)
range2 = range(2,6)
concatenated = set.union(set(range1), set(range2)
for i in concatenated:
print(i)
Je sais que c'est un peu vieux fil, mais pour moi, ce qui suit fonctionne.
>>> for i in range(30) + range(2000, 5002):
... print i
Ainsi fait ceci
>>> for i in range(30) , range(2000, 5002):
... print i
Bien sûr, la sortie d’impression est différente entre le deuxième et le premier.
Edit: j’ai manqué le commentaire suivant dans le PO indiquant Python 3. C’est dans mon environnement Python 2.