114 votes

Y a-t-il un besoin de range(len(a))?

On trouve fréquemment des expressions de ce type dans les questions python sur SO. Que ce soit pour accéder à tous les éléments de l'itérable

for i in range(len(a)):
    print(a[i])

Ce qui est simplement une façon maladroite d'écrire:

for e in a:
    print(e)

Ou pour assigner des éléments de l'itérable:

for i in range(len(a)):
    a[i] = a[i] * 2

Ce qui devrait être le même que:

for i, e in enumerate(a):
     a[i] = e * 2
# Ou si ce n'est pas trop coûteux de créer un nouvel itérable
a = [e * 2 for e in a]

Ou pour filtrer sur les indices:

for i in range(len(a)):
    if i % 2 == 1: continue
    print(a[i])

Ce qui pourrait être exprimé comme ceci:

for e in a [::2]:
    print(e)

Ou lorsque vous avez juste besoin de la longueur de la liste, et pas de son contenu:

for _ in range(len(a)):
    faireQuelqueChoseNonLiéA()

Ce qui pourrait être:

for _ in a:
    faireQuelqueChoseNonLiéA()

En python nous avons enumerate, le slicing, filter, sorted, etc... Comme les constructions for en python sont destinées à itérer sur des itérables et non seulement des plages d'entiers, y a-t-il des cas d'utilisation réels où vous avez besoin de in range(len(a))?

2voto

CleoR Points 596

C'est pratique lorsque vous avez besoin d'utiliser l'indice pour une manipulation quelconque et que l'élément actuel ne suffit pas. Prenons par exemple un arbre binaire stocké dans un tableau. Si vous avez une méthode qui vous demande de retourner une liste de tuples contenant les enfants directs de chaque nœud, alors vous avez besoin de l'indice.

#0 -> 1,2 : 1 -> 3,4 : 2 -> 5,6 : 3 -> 7,8 ...
nodes = [0,1,2,3,4,5,6,7,8,9,10]
children = []
for i in range(len(nodes)):
  leftNode = None
  rightNode = None
  if i*2 + 1 < len(nodes):
    leftNode = nodes[i*2 + 1]
  if i*2 + 2 < len(nodes):
    rightNode = nodes[i*2 + 2]
  children.append((leftNode,rightNode))
return children

Bien sûr, si l'élément sur lequel vous travaillez est un objet, vous pouvez simplement appeler une méthode getChild. Mais oui, vous avez vraiment besoin de l'indice seulement si vous effectuez une sorte de manipulation.

2voto

muntoo Points 4905

Parfois, vous ne vous souciez vraiment pas de la collection elle-même. Par exemple, en créant une simple ligne de modèle d'ajustement pour comparer une "approximation" avec les données brutes :

fib_raw = [1, 1, 2, 3, 5, 8, 13, 21] # Nombres de Fibonacci

phi = (1 + sqrt(5)) / 2
phi2 = (1 - sqrt(5)) / 2

def fib_approx(n): return (phi**n - phi2**n) / sqrt(5)

x = range(len(data))
y = [fib_approx(n) for n in x]

# Maintenant tracé pour comparer fib_raw et y
# Comparer l'erreur, etc

Dans ce cas, les valeurs de la séquence de Fibonacci elle-même étaient sans importance. Tout ce dont nous avions besoin ici était la taille de la séquence d'entrée avec laquelle nous comparions.

1voto

alartur Points 379

Si vous devez itérer sur les premiers len(a) éléments d'un objet b (qui est plus grand que a), vous devriez probablement utiliser range(len(a)):

for i in range(len(a)):
    faire_quelque_chose_avec(b[i])

0voto

Jim Points 17

J'ai un cas d'utilisation que je ne crois pas couvert par vos exemples.

boxes = [b1, b2, b3]
items = [i1, i2, i3, i4, i5]
for j in range(len(boxes)):
    boxes[j].putitemin(items[j])

Je suis relativement nouveau en python donc je suis heureux d'apprendre une approche plus élégante.

0voto

IARI Points 441

Exemple très simple :

def loadById(self, id):
    if id in range(len(self.itemList)):
        self.load(self.itemList[id])

Je ne peux pas penser à une solution qui n'utilise pas rapidement la composition range-len.

Mais probablement cela devrait être fait avec try .. except pour rester pythonique je suppose..

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X