[Python]Waarom werkt dit niet (highest even function)

Pagina: 1
Acties:

Onderwerpen

Vraag


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Python:
1
2
3
4
5
def highest_even(list):
  for number in list:
    if (number % 2 != 0):
      list.remove(number)
  return max(list)



print(highest_even([5,4,8,9,17]))

wanneer ik dit programma run op repl.it geeft hij 17
wanneer ik de list bekijk waaruit hij de max pakt zie ik dat alle oneven getallen worden verwijdert behalve de 17. Hoe kan dat?

[ Voor 3% gewijzigd door Woy op 11-05-2020 17:08 ]

Beste antwoord (via Verwijderd op 11-05-2020 19:14)


  • pedorus
  • Registratie: Januari 2008
  • Niet online
ViNyL schreef op maandag 11 mei 2020 @ 17:03:
Moet je de functie zelf na de remove niet opnieuw aanroepen?

code:
1
2
3
4
5
6
7
def highest_even(list):
  for number in list:
    if (number % 2 != 0):
      list.remove(number)
      highest_even(list)
  return max(list)
print(highest_even([5,4,8,9,17]))


Dit levert bij mij 8 op
Interessante oplossing, maar dit is heftig in-efficiënt en levert op een gegeven moment een stack overflow op. Per niet-even element heb je een call en veel getallen worden onnodig dubbel gecheckt. Dit is echt een mooie om met een debugger eens per stap doorheen te lopen om te zien wat er nu echt gebeurd.
nescafe schreef op maandag 11 mei 2020 @ 17:03:
Python:
1
2
3
4
5
6
7
8
def highest_even(list):
  for number in list.copy():
    if (number % 2 != 0):
      list.remove(number)
  return max(list)


print(highest_even([5,4,8,9,17]))
Op zich werkt dit ook, maar dit is ook niet efficiënt. Per element dat verwijderd moet worden moet je nogmaals op zoek naar dat element.

Ik zou me ook afvragen of je list eigenlijk wel zou mogen wijzigen bij zo'n functie, ik zou eigenlijk verwachten bij zo'n functie dat list niet gewijzigd wordt. Dus na
Python:
1
2
3
l=[5,4,8,9,17]
print(highest_even(l))
l

Zou ik verwachten dat je nog de oude l wil zien.

De genoemde List comprehensions lijkt me de aangewezen oplossing.
spoiler:
return max(x for x in list if x % 2 == 0)

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten

Alle reacties


Acties:
  • 0 Henk 'm!

  • Paling1
  • Registratie: Juni 2001
  • Niet online

Paling1

R 8.5

Wordt die for loop nog ergens afgesloten? (anders is 17 namelijk het juiste antwoord maar zou er misschien een foutmelding moeten zijn voor de for loop)
Welke script/programmeer taal is dit?

[ Voor 47% gewijzigd door Paling1 op 11-05-2020 16:58 ]


Acties:
  • 0 Henk 'm!

  • ViNyL
  • Registratie: Augustus 2001
  • Niet online
Moet je de functie zelf na de remove niet opnieuw aanroepen?

code:
1
2
3
4
5
6
7
def highest_even(list):
  for number in list:
    if (number % 2 != 0):
      list.remove(number)
      highest_even(list)
  return max(list)
print(highest_even([5,4,8,9,17]))


Dit levert bij mij 8 op

Acties:
  • +5 Henk 'm!

  • nescafe
  • Registratie: Januari 2001
  • Laatst online: 15:35
Het probleem is dat je tijdens het itereren de onderliggende collectie wijzigt.

Daardoor slaat python items 'over' (de lijst wordt kleiner maar de huidige index blijft hetzelfde).

Je zou dit op kunnen lossen door te itereren over een kopie van de collectie:

Python:
1
2
3
4
5
6
7
8
def highest_even(list):
  for number in list.copy():
    if (number % 2 != 0):
      list.remove(number)
  return max(list)


print(highest_even([5,4,8,9,17]))

* Barca zweert ook bij fixedsys... althans bij mIRC de rest is comic sans


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Sowieso zou ik gewoon gebruik maken van list comprehension of de filter functie. Zoals @nescafe aanhaalt is het niet verstandig om op deze manier een lijst te wijzigen terwijl je er overheen aan het itereren bent.

Verder zou je in het vervolg gebruik kunnen maken van de [code=python][/code] (dat heb ik nu voor je toegevoegd ) tags, en graag in je titel en post zelf vermelden over welke taal het gaat, dat maakt het makkelijker om je te helpen.

[ Voor 4% gewijzigd door Woy op 11-05-2020 17:08 ]

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • Orion84
  • Registratie: April 2002
  • Laatst online: 16:09

Orion84

Admin General Chat / Wonen & Mobiliteit

Fotogenie(k)?

Om te begrijpen wat er precies gebeurt en te debuggen zou je eens aan het begin van je for loop (voor de if) het 'number' moeten printen en na de list.remove de list printen. Zodat je ziet welke items hij bekijkt en wat er dan nog over blijft van de lijst.

The problem with common sense is that it's not all that common. | LinkedIn | Flickr


Acties:
  • +2 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Orion84 schreef op maandag 11 mei 2020 @ 17:12:
Om te begrijpen wat er precies gebeurt en te debuggen zou je eens aan het begin van je for loop (voor de if) het 'number' moeten printen en na de list.remove de list printen. Zodat je ziet welke items hij bekijkt en wat er dan nog over blijft van de lijst.
Of gebruik maken van een step through debugger. Printen is natuurlijk prima, maar leren hoe je echt kunt debuggen is een waardevolle les

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • Beste antwoord
  • +1 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
ViNyL schreef op maandag 11 mei 2020 @ 17:03:
Moet je de functie zelf na de remove niet opnieuw aanroepen?

code:
1
2
3
4
5
6
7
def highest_even(list):
  for number in list:
    if (number % 2 != 0):
      list.remove(number)
      highest_even(list)
  return max(list)
print(highest_even([5,4,8,9,17]))


Dit levert bij mij 8 op
Interessante oplossing, maar dit is heftig in-efficiënt en levert op een gegeven moment een stack overflow op. Per niet-even element heb je een call en veel getallen worden onnodig dubbel gecheckt. Dit is echt een mooie om met een debugger eens per stap doorheen te lopen om te zien wat er nu echt gebeurd.
nescafe schreef op maandag 11 mei 2020 @ 17:03:
Python:
1
2
3
4
5
6
7
8
def highest_even(list):
  for number in list.copy():
    if (number % 2 != 0):
      list.remove(number)
  return max(list)


print(highest_even([5,4,8,9,17]))
Op zich werkt dit ook, maar dit is ook niet efficiënt. Per element dat verwijderd moet worden moet je nogmaals op zoek naar dat element.

Ik zou me ook afvragen of je list eigenlijk wel zou mogen wijzigen bij zo'n functie, ik zou eigenlijk verwachten bij zo'n functie dat list niet gewijzigd wordt. Dus na
Python:
1
2
3
l=[5,4,8,9,17]
print(highest_even(l))
l

Zou ik verwachten dat je nog de oude l wil zien.

De genoemde List comprehensions lijkt me de aangewezen oplossing.
spoiler:
return max(x for x in list if x % 2 == 0)

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • Butsnik
  • Registratie: Juli 2015
  • Laatst online: 14:05
Mocht je bij je for loop willen blijven dan zou je het ook om kunnen draaien en de mogelijke candidaten aan een lijst toevoegen waar je dan de max in zoekt:

Python:
1
2
3
4
5
6
7
8
9
def highest_even(list):
  even = []
  for number in list:
    if (number % 2 == 0):
      even.append(number)
  return max(even)


print(highest_even([5,4,8,9,17]))


Maar zoals gezegd is het gebruiken van list comprehensions het beste.

Acties:
  • 0 Henk 'm!

  • Orion84
  • Registratie: April 2002
  • Laatst online: 16:09

Orion84

Admin General Chat / Wonen & Mobiliteit

Fotogenie(k)?

Butsnik schreef op woensdag 13 mei 2020 @ 13:50:
Mocht je bij je for loop willen blijven dan zou je het ook om kunnen draaien en de mogelijke candidaten aan een lijst toevoegen waar je dan de max in zoekt:

Python:
1
2
3
4
5
6
7
8
9
def highest_even(list):
  even = []
  for number in list:
    if (number % 2 == 0):
      even.append(number
  return max(even)


print(highest_even([5,4,8,9,17]))

Maar zoals gezegd is het gebruiken van list comprehensions het beste.
Dat is inderdaad een stuk netter dan on the fly de lijst aanpassen waarover je aan het itereren bent ja. Wel ten koste van wat extra geheugengebruik. Je mist overigens wel een sluithaakje op regel 5 :>

Je zou ook gewoon in de for loop het maximum bij kunnen houden, scheelt je een kopie van de lijst bijhouden en scheelt ook dat je daarna niet nog weer een max functie moet toepassen die nog eens door de lijst moet.

[ Voor 14% gewijzigd door Orion84 op 13-05-2020 13:56 ]

The problem with common sense is that it's not all that common. | LinkedIn | Flickr


Acties:
  • 0 Henk 'm!

  • bwerg
  • Registratie: Januari 2009
  • Niet online

bwerg

Internettrol

Orion84 schreef op woensdag 13 mei 2020 @ 13:55:
Je zou ook gewoon in de for loop het maximum bij kunnen houden, scheelt je een kopie van de lijst bijhouden en scheelt ook dat je daarna niet nog weer een max functie moet toepassen die nog eens door de lijst moet.
Daar zou ik ook voor stemmen. Prachtig, list comprehensions en lijsten kopieëren, maar gewoon door een lijstje lopen met een for-loopje en een resultaat bijhouden lijkt me les 1. Dan kan je altijd nog naar list comprensions wanneer dat écht handiger is.

Heeft geen speciale krachten en is daar erg boos over.

Pagina: 1