[Python]Gebruik map() begrijpen (om for-lus te vervangen)

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • kramer65
  • Registratie: Oktober 2003
  • Laatst online: 27-05 20:45
Hallo,

Gezien ik begrijp dat map() in Python vele malen sneller is dan een for-lus wil ik de map() functie een beetje begrijpen. Ik heb hiervoor een twee-dimensionaal dictionary gemaakt welke ik uitlees met een dubbele for-lus:

Python:
1
2
3
4
5
6
7
8
9
10
11
12
def print_all():
    print(date)
    print(each_time)
    print(time[each_time])

price_dict = {'1997-05-28': {'09:02:00': 74.54, '09:01:00': 77.22},
'1997-05-29': {'09:02:00': 76.98, '09:01:00': 77.34, '09:03:00':79.23},
'1997-05-30': {'09:03:00': 80.12, '09:01:00': 78.27, '09:02:00': 79.94}}
stop_laag = 77
for date, time in sorted(price_dict.iteritems()):
    for each_time in sorted(time.iterkeys()):
        print_all()

Vervolgens heb ik in de functie het argument "w" toegevoegd, heb ik de derde regel van de print's in de functie weggecomment(#), en heb ik de tweede for-lus voor een map() vervangen:
Python:
1
2
3
4
5
6
7
8
9
10
11
def print_all(w):
    print(date)
    print(each_time)
    #print(time[each_time])

price_dict = {'1997-05-28': {'09:02:00': 74.54, '09:01:00': 77.22},
'1997-05-29': {'09:02:00': 76.98, '09:01:00': 77.34, '09:03:00':79.23},
'1997-05-30': {'09:03:00': 80.12, '09:01:00': 78.27, '09:02:00': 79.94}}
stop_laag = 77
for date, time in sorted(price_dict.iteritems()):
    map(print_all, sorted(time.iterkeys()))

Dit werkt allemaal prima.

Zoals je misschien wel had verwacht heb ik vervolgens het hekje (#) voor de laatste print in de functie weggehaald. Dit resulteerd echter in de volgende error:
Python:
1
2
3
map(print_all, sorted(time.iterkeys()))
print(time[each_time])
KeyError: '09:03:00'

Ik begrijp niet helemaal waarom ik hiervoor een error krijg. Dit omdat het wèl prima werkt wanneer de functie in de for-lus gebruikt wordt.

Heeft iemand enig idee wat ik hier fout doe?

Acties:
  • 0 Henk 'm!

  • Windows95
  • Registratie: Mei 2010
  • Laatst online: 06-06 11:56
Verander:
def print_all(w):
in:
def print_all(each_time)

Acties:
  • 0 Henk 'm!

  • mindcrash
  • Registratie: April 2002
  • Laatst online: 22-11-2019

mindcrash

Rebellious Monkey

Het probleem zit 'm in dit

Python:
1
2
3
for date, time in sorted(price_dict.iteritems()):
    for each_time in sorted(time.iterkeys()):
        print_all()


versus dit:

Python:
1
2
for date, time in sorted(price_dict.iteritems()):
    map(print_all, sorted(time.iterkeys()))


(hint: waar is je each_time gebleven? en handig erhm... 'gebruik' maken van variable scope is over het algemeen ook niet zo heel erg handig)

[ Voor 37% gewijzigd door mindcrash op 29-11-2011 07:44 ]

"The people who are crazy enough to think they could change the world, are the ones who do." -- Steve Jobs (1955-2011) , Aaron Swartz (1986-2013)


Acties:
  • 0 Henk 'm!

  • kramer65
  • Registratie: Oktober 2003
  • Laatst online: 27-05 20:45
Ah, ja! Je hebt gelijk! Dus hij moet zo zijn:
Python:
1
2
3
4
5
6
7
8
9
10
11
def print_all(each_time):
    print(date)
    print(each_time)
    print(price_dict[date][each_time])

price_dict = {'1997-05-28': {'09:02:00': 74.54, '09:01:00': 77.22},
'1997-05-29': {'09:02:00': 76.98, '09:01:00': 77.34, '09:03:00':79.23},
'1997-05-30': {'09:03:00': 80.12, '09:01:00': 78.27, '09:02:00': 79.94}}

for date, time in sorted(price_dict.iteritems()):
    map(print_all, sorted(time.iterkeys()))

Dom, dat ik dat over het hoofd zag, dank voor de tip!

Nog een vraagje. Als ik nou die tweede for-lus óók in een map wil hebben staan, zou dat mogelijk zijn?
Ik heb het eens geprobeerd door het volgende te doen:

Python:
1
2
3
4
5
6
7
8
9
10
11
12
13
price_dict = {'1997-05-28': {'09:02:00': 74.54, '09:01:00': 77.22},
'1997-05-29': {'09:02:00': 76.98, '09:01:00': 77.34, '09:03:00':79.23},
'1997-05-30': {'09:03:00': 80.12, '09:01:00': 78.27, '09:02:00': 79.94}}

def print_all(each_time):
    print(date)
    print(each_time)
    print(price_dict[date][each_time])

def everything_in_one(time):
    map(print_all, sorted(time.iterkeys()))

map(everything_in_one,sorted(price_dict.iteritems()))

Nu geeft hij echter het volgende aan: AttributeError: 'tuple' object has no attribute 'iterkeys'. Voor zover ik begrijp maakt hij dus ergens een tuple aan. Ik lees echter in de documentatie dat map() een list aanmaakt, en geen tuple. Of maakt map() bij een dictionary een list van tuples aan met elk twee elementen erin?

Ik las ergens dat map() op zich niet zo moeilijk is, maar vooral begrepen moet worden. Dat laatste punt begrijp ik nu in ieder geval wel.. 8)7

Acties:
  • 0 Henk 'm!

  • ValHallASW
  • Registratie: Februari 2003
  • Niet online
Python:
1
result = map(f, iterable)


is hetzelfde als

Python:
1
result = [f(item) for item in iterable]


is hetzelfde als

code:
1
2
3
result = []
for item in iterable:
  result.append(f(item))


waarbij de tweede variant de meest gebruikte en meest leesbare is.


Je foutmelding komt doordat price_dict.iteritems() een iterator met twee-tuples (key, value) retourneert, en je die vervolgens doorgeeft.


Last but not least: je werkt in python. Ga *niet* dit soort premature optimalisaties maken, zeker aangezien het in python 1) weinig uitmaakt en het 2) alsnog traag is vergeleken met een C-implementatie. Ga eerst je programma schrijven, dan profilen en dan eventueel optimaliseren.

Acties:
  • 0 Henk 'm!

  • kramer65
  • Registratie: Oktober 2003
  • Laatst online: 27-05 20:45
Dank voor de tips. Ik ga er nog eens stevig doorheen waden en wat meer lezen.
ValHallASW schreef op dinsdag 29 november 2011 @ 13:02:
Last but not least: je werkt in python. Ga *niet* dit soort premature optimalisaties maken, zeker aangezien het in python 1) weinig uitmaakt en het 2) alsnog traag is vergeleken met een C-implementatie. Ga eerst je programma schrijven, dan profilen en dan eventueel optimaliseren.
Ik kom ook wel eens uitspraken tegen als "doe het vanaf het begin goed". Vandaar dat ik meteen eens met map() aan de gang wilde gaan. Maar wat je zegt is misschien wel waar. Ik zal eerst het programma wat ik wil schrijven eens werkende maken, en daarna zal ik allerhande optimalisatie-trucs gaan toepassen.

Dank in ieder geval voor de helpende hand!

Acties:
  • 0 Henk 'm!

  • Tim
  • Registratie: Mei 2000
  • Laatst online: 18-03 14:00

Tim

Hoe kom je er bij dat map sneller is? map is een functie en heeft een list (of generator) als return value.

Het is zeker niet bedoeld om for loops te vervangen. Sterker nog, als het aan Guido van Rossum had gelegen, had map niet eens meer bestaan.

Acties:
  • 0 Henk 'm!

  • Wolfboy
  • Registratie: Januari 2001
  • Niet online

Wolfboy

ubi dubium ibi libertas

Voor het performance verschil hoef je echt geen map te gebruiken hoor... veel sneller is het echt niet.

Je moet zoiets voor de leesbaarheid/eenvoud doen, bijvoorbeeld als je een lijst met getallen hebt die omgezet moeten worden naar integers: "map(int, lijstje)"

Blog [Stackoverflow] [LinkedIn]

Pagina: 1