1

I THINK DUPLICATE FROM

Remove items from a list while iterating

where best solution is:

somelist[:] = [tup for tup in somelist if determine(tup)]

I don't understand in deepth how it works, but seems to work !!!

NOW I understand how it works !! (2017/02/05)

I'm a python beginner and I find something maybe ot strange in list iteration and deletion. Here is my code:

# -*- coding: utf-8 -*-s
#
# Fichier: testques.py
#

liste = [0,1,2,3,4,5,6,7,8,9]

cpt1=0
cpt2=0
cpt3=len(liste)

for i in liste:
    if i != 2:
        cpt1 += 1
    else:
        cpt2 += 1
        del liste[i]

print cpt1
print cpt2
print cpt3

>python test.py
8
1
10

As you can see, 8+1 is not 10.

My thing is that "i" is only a reference to a list index. When I delete the element list, then all elements below the one I delete go up one level and then just next one is not parse by for ... in.

Then can somebody help me to achieve the goal of having at the end the following result: 9 1 10

EDIT AFTER 3 ANSWERS My goal is not counting number of elements equal to 2.

In fact, each element of my list is a dictionnary, and I want to delete all list items where the value for the xxx key of each dictionnary is no exactly 7 digits. And after I'll do others operations on the now clean list. This is what i try to achieve.

Sorry for not havjng been enough clear in first question.

Here is my real code:

cpt = 0
liste_longueur_totale = len(i)
liste_longueur_clean = 0
liste_delete = 0
numero = re.compile('^[0-9]{7}$')
for row in i:
    if re.match(numero, row['j_numero']):
        liste_longueur_clean += 1
        cpt += 1
    else:
        liste_delete += 1
        print liste_delete, '-', i[cpt]['j_id'], '-', i[cpt]['j_numero']
        del i[cpt]
        cpt += 1
print "%s : %s + %s" % (liste_longueur_totale,liste_longueur_clean,liste_delete )
print len(i)

"i" is a list of 703 items. Each one is a dictionnary.

When I run it, I've the following result:

703: 673 + 15
688

When I run the same code without the line:

del i[cpt]

I've the following result:

703: 681 + 21
703

An in fact I know that 21 items are not responding to the re.match()

Then, I'm a little perplex !!!

Community
  • 1
  • 1
Youpsla
  • 159
  • 2
  • 13

4 Answers4

1

Forget doing it the hard way. Especially if your list isn't so long that iterating over it multiple times is a big deal.

cpt1 = sum(1 for x in liste if x != 2)
cpt2 = sum(1 for x in liste if x == 2)
Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
1

You can simply make a copy of the list before iterating and removing elements from it:

liste = [0,1,2,3,4,5,6,7,8,9]

cpt1=0
cpt2=0
cpt3=len(liste)

# Just add [:] here. See explanation below.
for i in liste[:]:
    if i != 2:
        cpt1 += 1
    else:
        cpt2 += 1
        del liste[i]

print cpt1
print cpt2
print cpt3

list[:] is a well-known idiom for copying lists. It's actually a slice from the first to the last element, with the result of returning a new list with all elements from the original.

BoppreH
  • 8,014
  • 4
  • 34
  • 71
0

Actually i is not a reference to a list index, it is the list item, so when you delete it you make your list shorter, len(liste)=9, if you want just an array of list indices use enumerate(liste) instead, although I don't see the point of deleting the index

  • I though about a reference because as you can see in the edit part of my question, I've different results depending on the delete function. – Youpsla Nov 23 '12 at 01:12
0

If you want to count how many 2's are in your list, you can simply type print liste.count(2) and you'll get 1. To get 9 you can either subtract len(liste) - liste.count(2) or follow the Ignacio solution: sum(1 for x in liste if x != 2).

aemdy
  • 3,702
  • 6
  • 34
  • 49