J'aimerais connaître la meilleure façon (façon plus compacte et "pythonique") de faire un traitement spécial pour le dernier élément d'une boucle for. Il y a un morceau de code qui ne devrait être appelé qu'entre éléments, étant supprimé dans le dernier.
Voici comment je le fais actuellement:
for i, data in enumerate(data_list):
code_that_is_done_for_every_element
if i != len(data_list) - 1:
code_that_is_done_between_elements
Y a-t-il une meilleure façon?
Remarque: je ne veux pas le faire avec des hacks tels que l'utilisation reduce
.;)
Réponses:
La plupart du temps, il est plus facile (et moins coûteux) de faire de la première itération le cas particulier au lieu du dernier:
Cela fonctionnera pour tout itérable, même pour ceux qui n'ont pas
len()
:En dehors de cela, je ne pense pas qu'il existe une solution généralement supérieure car cela dépend de ce que vous essayez de faire. Par exemple, si vous construisez une chaîne à partir d'une liste, il est naturellement préférable d'utiliser
str.join()
unefor
boucle «avec cas particulier».En utilisant le même principe mais plus compact:
Cela semble familier, n'est-ce pas? :)
Pour @ofko, et d'autres qui ont vraiment besoin de savoir si la valeur actuelle d'un itérable sans
len()
est la dernière, vous devrez regarder vers l'avenir:Ensuite, vous pouvez l'utiliser comme ceci:
la source
if
qui pourrait être évité si la boucle était divisée en deux boucles. Cependant, cela n'est pertinent que lors de l'itération d'une énorme liste de données.next()
. Ensuite, j'exploite qu'un itérateur est itérable par lui-même, donc je peux l'utiliser dans lafor
boucle jusqu'à épuisement, itération de la seconde à la dernière valeur. Pendant ce temps, je garde la valeur actuelle que j'ai récupérée de l'itérateur localement etyield
la dernière à la place. De cette façon, je sais qu'il y a encore une valeur à venir. Après la boucle for, j'ai signalé toutes les valeurs sauf la dernière.Bien que cette question soit assez ancienne, je suis venu ici via google et j'ai trouvé un moyen assez simple: le découpage de listes. Supposons que vous souhaitiez mettre un «&» entre toutes les entrées de la liste.
Cela renvoie «1 & 2 & 3».
la source
len(l)=1000000
dans cet exemple, le programme fonctionnera pendant un certain temps.append
est recommandé afaik.l=[1,2,3]; l.append(4);
Le «code entre» est un exemple du modèle Head-Tail .
Vous avez un élément, qui est suivi d'une séquence de paires (entre, éléments). Vous pouvez également afficher cela sous la forme d'une séquence de paires (d'éléments, entre) suivies d'un élément. Il est généralement plus simple de prendre le premier élément comme spécial et tous les autres comme le cas «standard».
De plus, pour éviter de répéter du code, vous devez fournir une fonction ou un autre objet pour contenir le code que vous ne voulez pas répéter. Incorporer une instruction if dans une boucle qui est toujours fausse sauf une fois est un peu ridicule.
Ceci est plus fiable car c'est un peu plus facile à prouver, cela ne crée pas de structure de données supplémentaire (c'est-à-dire une copie d'une liste) et ne nécessite pas beaucoup d'exécution gaspillée d'une condition if qui est toujours fausse sauf une fois.
la source
if
instructions, donc l'argument «exécution gaspillée» ne tient pas.if
secondes». De toute évidence, vous faites simplement référence à la «propreté du code»?if
instruction est-elle vraiment considérée comme plus propre par la communauté Python?Si vous cherchez simplement à modifier le dernier élément,
data_list
vous pouvez simplement utiliser la notation:Cependant, il semble que vous faites plus que cela. Il n'y a rien de vraiment mal avec votre chemin. J'ai même jeté un coup d'œil rapide sur du code Django pour leurs balises de modèle et ils font essentiellement ce que vous faites.
la source
if data != datalist[-1]:
et garder tout le reste pareil serait le meilleur moyen de coder cela à mon avis.si les éléments sont uniques:
autres options:
la source
Ceci est similaire à l'approche d'Ants Aasma mais sans utiliser le module itertools. C'est aussi un itérateur en retard qui anticipe un seul élément dans le flux d'itérateur:
la source
Vous pouvez utiliser une fenêtre glissante sur les données d'entrée pour avoir un aperçu de la valeur suivante et utiliser une sentinelle pour détecter la dernière valeur. Cela fonctionne sur n'importe quel itérable, vous n'avez donc pas besoin de connaître la longueur au préalable. L'implémentation par paires provient des recettes itertools .
la source
N'y a-t-il pas de possibilité d'itérer sur tout sauf le dernier élément, et de traiter le dernier en dehors de la boucle? Après tout, une boucle est créée pour faire quelque chose de similaire à tous les éléments sur lesquels vous bouclez; si un élément a besoin de quelque chose de spécial, il ne devrait pas être dans la boucle.
(voir aussi cette question: est-ce-que-le-dernier-élément-dans-une-boucle-mérite-un-traitement-séparé )
EDIT: puisque la question porte davantage sur l '«entre», soit le premier élément est le spécial en ce qu'il n'a pas de prédécesseur, soit le dernier élément est spécial en ce qu'il n'a pas de successeur.
la source
J'aime l'approche de @ ethan-t, mais
while True
c'est dangereux de mon point de vue.Ici,
data_list
c'est pour que le dernier élément soit égal en valeur au premier de la liste. L peut être échangé avecdata_list
mais dans ce cas il est vide après la boucle.while True
est également possible d'utiliser si vous vérifiez que la liste n'est pas vide avant le traitement ou si la vérification n'est pas nécessaire (aïe!).La bonne partie est que c'est rapide. Le mauvais - il est destructible (
data_list
devient vide).Solution la plus intuitive:
Oh oui, vous l'avez déjà proposé!
la source
Il n'y a rien de mal dans votre chemin, à moins que vous n'ayez 100 000 boucles et que vous vouliez enregistrer 100 000 instructions «si». Dans ce cas, vous pouvez procéder comme suit:
Les sorties :
Mais vraiment, dans votre cas, j'ai l'impression que c'est exagéré.
Dans tous les cas, vous aurez probablement plus de chance avec le tranchage:
ou juste :
Finalement, une façon KISS de faire vos choses, et cela fonctionnerait avec n'importe quel itérable, y compris ceux sans
__len__
:Sorties:
Si j'ai l'impression que je le ferais de cette façon, cela me semble simple.
la source
item
au lieu de le recalculer aveclist[-1]
. Mais néanmoins: je ne pense pas que ce soit ce que le PO demandait, n'est-ce pas?iterable.__iter__()
- veuillez ne pas appeler les__
fonctions directement. Devrait êtreiter(iterable)
.Utilisez le tranchage et
is
pour vérifier le dernier élément:Caveat emptor : Cela ne fonctionne que si tous les éléments de la liste sont réellement différents (ont des emplacements différents en mémoire). Sous le capot, Python peut détecter des éléments égaux et réutiliser les mêmes objets pour eux. Par exemple, pour des chaînes de même valeur et des entiers communs.
la source
si vous parcourez la liste, cela a aussi fonctionné pour moi:
la source
Google m'a amené à cette vieille question et je pense que je pourrais ajouter une approche différente à ce problème.
La plupart des réponses ici concerneraient un traitement approprié d'un contrôle de boucle for comme cela a été demandé, mais si la data_list est destructible, je vous suggère de faire apparaître les éléments de la liste jusqu'à ce que vous vous retrouviez avec une liste vide:
vous pouvez même utiliser while len (element_list) si vous n'avez rien à faire avec le dernier élément. Je trouve cette solution plus élégante que de traiter avec next ().
la source
Pour moi, le moyen le plus simple et le plus pythonique de gérer un cas particulier à la fin d'une liste est:
Bien entendu, cela peut également être utilisé pour traiter le premier élément d'une manière spéciale.
la source
Au lieu de compter, vous pouvez également compter à rebours:
la source
Retardez le traitement spécial du dernier élément jusqu'après la boucle.
la source
Il peut y avoir plusieurs façons. le tranchage sera le plus rapide. Ajout d'un autre qui utilise la méthode .index ():
la source
En supposant que l'entrée soit un itérateur, voici un moyen d'utiliser tee et izip d'itertools:
Démo:
la source
La solution la plus simple qui me vient à l'esprit est:
Nous regardons donc toujours en avant un élément en retardant le traitement d'une itération. Pour ne pas faire quelque chose lors de la première itération, j'attrape simplement l'erreur.
Bien sûr, vous devez réfléchir un peu, pour que le
NameError
soit élevé quand vous le souhaitez.Gardez également le `counstruct
Cela suppose que le nom new n'a pas été défini auparavant. Si vous êtes paranoïaque, vous pouvez vous assurer que cela
new
n'existe pas en utilisant:Alternativement, vous pouvez bien sûr également utiliser une instruction if (
if notfirst: print(new) else: notfirst = True
). Mais pour autant que je sache, les frais généraux sont plus importants.je m'attends donc à ce que les frais généraux ne soient pas sélectionnables.
la source
Comptez les articles une fois et suivez le nombre d'articles restants:
De cette façon, vous n'évaluez qu'une seule fois la longueur de la liste. La plupart des solutions de cette page semblent supposer que la longueur n'est pas disponible à l'avance, mais cela ne fait pas partie de votre question. Si vous avez la longueur, utilisez-la.
la source
Une solution simple qui me vient à l'esprit serait:
Une deuxième solution tout aussi simple pourrait être obtenue en utilisant un compteur:
la source