Fördefinierade nästlade strukturer
Skriv lösningarna till uppgifterna i en och samma fil och testa koden själv innan du använder rättningsskriptet. Att kunna testa sin kod är en viktig del av att programmera!
Att lära dig från uppgifterna
- Bearbeta data bestående av listor i listor med en nivå av nästling.
- Slå upp data JSON-liknande strukturer med multipla nivåer av listor och dictionaries.
- Lösa problem som kräver hantering av data på flera nivåer av nästling samtidigt.
- Lösa problem i nästlade strukturer med hjälp av nästlade loopar.
Man kan få max 210 poäng och för att få godkänt krävs 70 poäng (165 för väl godkänt). Försök dock att lösa alla uppgifter då inte alla fel upptäcks av rättningsskriptet. Om ni har lite marginal kan ni kanske bli godkända även om assistenten som rättar hittar något sådant fel.
Introduktion
De inledande uppgifterna fokuserar på generella principer för att hantera nästlade data följt av ett antal större uppgifter på mer verklighetsnära data.
Den totala poängen för samtliga uppgifter är högre än tidigare, men antalet uppgifter man behöver lösa för att skrapa ihop de nödvändiga poängen är färre. Uppgifternas poäng speglar inte längre enbart svårighetsgrad utan också vilka uppgifter som är viktigast. Dvs. man ska inte tolka det som att en uppgift som ger 30 poäng är 6 gånger svårare än en uppgift som ger 5 poäng. Man ska inte heller tolka det som att alla uppgifter som ger 5 poäng är ungefär lika svåra.
Poängen på uppgifterna är satta så att det ska gå att få godkänt genom att bara lösa någon av de avslutande uppgifterna i sin helhet (med alla deluppgifter) givet att man löst de inledande uppgifterna. Det är dock rekommenderat att, när man har tid, lösa fler uppgifter för att förbereda sig inför duggan.
Det går att bli godkänd på detta kapitel utan att lösa någon av 30-poängsuppgifterna, men det är markant svårare och man kommer inte vara lika väl förberedd inför duggan där ni kommer behöva lösa minst en uppgift av den typen för att bli godkända.
Uppgifter
Uppgift 11.1 (5p)
Skriv funktionen sum_of_ints2(value_list)
som tar in en lista med listor av värden som argument. Funktionen ska returnera summan av alla heltal som finns i de nästlade listorna.
Exempel
>>> sum_of_ints2([["a", 1], [2, 3.0, "hej"]])
3
Uppgift 11.2 (5p)
Skriv funktionen flatten_list1(list_of_lists)
som får in en nästlad lista. De
inre listorna innehåller inga listor. Funktionen ska returnera en icke-nästlad
lista som innehåller alla värden i de inre listorna.
Om list_of_values
är [[1, 2], [3], [1, 2, 3]]
så ska funktionen returnera
listan [1, 2, 3, 1, 2, 3]
.
Uppgift 11.3 (10p)
Skriv funktionen flatten_list2(list_of_lists)
som får in en lista som både
innehåller listor och vanliga värden. De inre listorna innehåller dock inga
listor. Funktionen ska returnera en icke-nästlad lista som innehåller alla
värden i de inre listorna, samt värdena som ligger direkt i listan.
Om list_of_values
är [[1, 2], [3], 4, [1, 2, 3], 4, 5]
så ska funktionen
returnera listan [1, 2, 3, 4, 1, 2, 3, 4, 5]
.
Uppgift 11.4 (10p)
Skriv funktionen add_to_value_list(key, value, d)
som tar in ett nyckel, ett
värde och ett dictionary. Värdena i dictionaryt kommer att vara listor (du
behöver inte kontrollera detta) och den angivna nyckeln kommer att finnas.
Värdet ska läggas till till listan som tillhör nyckeln key
i dictionaryt.
Funktionen behöver inte returnera dictionaryt.
Uppgift 11.5 (10p)
Skriv funktionen values_of_keys_matching(prefix, d)
som tar in en sträng och ett dictionary. Funktionen ska returnera en tupel som innehåller alla värden som tillhör nycklar som börjar på strängen prefix
. Alla nycklar i d
kommer att vara strängar.
Exempel
>>> d = {
"car_red": "Volvo",
"car_blue": "BMW",
"car_green": "Toyota",
"bike_red": "Crescent",
"bus_yellow": "Scania"
}
>>> print(values_of_keys_matching("car_", d))
("Volvo", "BMW", "Toyota")
Uppgift 11.6 (10p)
Skriv funktionen value_exists2(value, d)
som tar in ett dictionary och
returnerar True
om värdet value
finns bland dictionaryts värden.
Returnera False
om det inte finns.
Dictionaryts värden ska kunna vara siffror, strängar eller icke-nästlade listor.
Funktionen ska även leta efter värdet value
i eventuella listor. Om vi letar
efter värdet 'hejsan'
i dictionaryt
|
|
Konkreta datastrukturer
Var och en av de resterande uppgifterna består av flera deluppgifter som bearbetar samma nästlade datastruktur. Uppgifterna inleds med ett antal mindre deluppgifter för att bekanta sig med datastrukturen och avslutas med en uppgift som kommer från en av de tidigare duggorna, men något omformaterad för att passa det här formatet.
Börja med att välja en av uppgifterna nedan att fokusera på. Läs igenom introduktionen och 30-poängsuppgiften. Försök att lösa 30-poängsuppgiften innan ni eventuellt gör de inledande 5-poängsuppgifterna.
Om ni kör fast kan ni göra några av 5-poängsuppgiftena för att få ledtrådar och öva på delproblem som kan behövas för att lösa 30-poängsuppgiften. Det är dock inte alla 5-poängsuppgifter som motsvarar delproblem i 30-poängsuppgiften.
På duggan får ni inte den här hjälpen att identifiera delproblemen så försök att identifiera och lösa delproblemen i 30-poängsuppgiften själva först, innan ni eventuellt gör de inledande uppgifterna.
OBS! Uppgifterna på duggan kommer inte använda något av dessa datasets utan istället använda andra datasets med liknande nästlingsstrukturer men andra teman.
Uppgifter, forts.
Uppgift 11.7
I en värld där alla människor har unika namn som skrivs med endast gemener, har vi lagrat namn på barn och deras föräldrar i strukturen nedan. Varje dictionary representerar ett barn med nycklarna 'name'
och 'parents'
. Barn kan ha en eller fler föräldrar.
|
|
Vi ska nu skriva funktioner som kan svara på några olika frågor med hjälp av data på det här formatet.
11.7.1 (5p)
Skriv en funktion get_all_parents(dataset)
som tar ett dataset enligt formatet ovan och returnerar en lista med alla föräldrar. Listan ska inte innehålla samma namn flera gånger. Ordningen av namnen i den returnerade listan spelar ingen roll.
Tips: Det kan vara lämpligt att lagra föräldrarna som en mängd inne i funktionen och konvertera till en lista när mängden ska returneras. En mängd (set
eller frozenset
) kan utökas på flera sätt, se t.ex. den officiella pythondokumentationen
Exempel
>>> get_all_parents(pop)
['riley', 'alex', 'jordan', 'parker', 'drew', 'rene']
11.7.2 (5p)
Skriv en funktion get_parents_of(child_name, dataset)
som tar namnet på ett barn och ett dataset enligt formatet ovan och returnerar en lista med föräldrarna till barnet med namnet child_name
. Om barnet inte finns i datasetet ska en tom lista returneras.
Exempel
>>> get_parents_of('robin', pop)
['riley', 'drew']
>>> get_parents_of('kirby', pop)
['drew', 'alex', 'parker']
11.7.3 (5p)
Skriv en funktion get_children_of(parent_name, dataset)
som tar namnet på en förälder och ett dataset enligt formatet ovan och returnerar en lista med barnen till föräldern med namnet parent_name
. Om föräldern inte finns i datasetet ska en tom lista returneras.
Exempel
11.7.4 (5p)
Skriv en funktion add_child(child_name, parents, dataset)
som tar en sträng child_name
, en lista av strängar parents
och ett dataset enligt ovan som argument. Funktionen ska lägga till barnet och dess föräldrar i datasetet. Antag att barnet inte finns i datasetet sedan tidigare. Funktionen ska inte returnera något.
Exempel
>>> add_child('river', ['riley'], pop)
>>> for person in pop: print(person)
{'name': 'robin', 'parents': ['riley', 'drew']}
{'name': 'dylan', 'parents': ['drew', 'rene', 'parker', 'jordan']}
{'name': 'carey', 'parents': ['riley', 'jordan']}
{'name': 'casey', 'parents': ['rene', 'alex']}
{'name': 'kirby', 'parents': ['drew', 'alex', 'parker']}
{'name': 'reese', 'parents': ['rene', 'drew']}
{'name': 'river', 'parents': ['riley']}
11.7.5 (5p)
Skriv en funktion add_parent(parent_name, child_name, dataset)
som tar en sträng parent_name
, en sträng child_name
och ett dataset enligt ovan som argument. Funktionen ska lägga till föräldern parent_name
till barnet child_name
i datasetet. Om barnet inte finns i datasetet ska det läggas till med föräldern parent_name
som enda förälder. Om föräldern redan finns bland barnets föräldrar ska inget göras.
Exempel
>>> add_parent('riley', 'river', pop)
>>> add_parent('drew', 'robin', pop)
>>> add_parent('jordan', 'robin', pop)
>>> for person in pop: print(person)
{'name': 'robin', 'parents': ['riley', 'drew', 'jordan']}
{'name': 'dylan', 'parents': ['drew', 'rene', 'parker', 'jordan']}
{'name': 'carey', 'parents': ['riley', 'jordan']}
{'name': 'casey', 'parents': ['rene', 'alex']}
{'name': 'kirby', 'parents': ['drew', 'alex', 'parker']}
{'name': 'reese', 'parents': ['rene', 'drew']}
{'name': 'river', 'parents': ['riley']}
11.7.6 (30p)
Den här uppgiften har tidigare varit med på duggan.
Två personer är syskon om de delar någon förälder. Skriv funktionen get_siblings_of(child, dataset)
där argumentet child
är namnet på ett barn och dataset
följer formatet ovan. Funktionen ska returnera en lista med namnen på syskon till child
. Ordningen på de returnerade namnen spelar ingen roll.
Antag att child
existerar i dataset
. OBS! En person räknas inte som syskon till sig själv och varje syskon ska bara förekomma en gång i den returnerade listan.
Tips: Om du löst get_parents_of
och get_children_of
kan du anropa dem för att lösa delar av problemet.
Exempel
|
|
Uppgift 11.8
En databas med recept kan representeras av ett dictionary på följande sätt:
|
|
11.8.1 (5p)
Skriv en funktion needed_ingredients(to_make, database)
som tar en lista med namn på recept och en receptdatabas enligt ovan. Funktionen ska returnera en lista på de ingredienser som behövs för att tillreda alla recept i to_make
. Antag att alla recept i to_make
finns i database
.
Tips: Det kan vara lämpligt att lagra ingredienserna som behövs som en mängd inne i funktionen och konvertera till en lista när mängden ska returneras. En mängd (set
eller frozenset
) kan utökas på flera sätt, se t.ex. den officiella pythondokumentationen
Exempel
>>> needed_ingredients(['kladdkaka'], recipe_db)
['socker', 'mjöl', 'kakao', 'smör']
>>> needed_ingredients(['mördegskakor', 'typ bröd'], recipe_db)
['socker', 'vatten', 'mjöl', 'smör']
11.8.2 (5p)
Skriv en funktion can_prepare(needed, pantry)
som tar en lista med ingredienserna som behövs för ett recept och ett “skafferi” med tillgängliga ingredienser. Funktionen ska returnera ett sanningsvärde som representerar huruvida receptet kan tillredas.
Vi gör det förenklande antagandet att om vi har tillgång till en ingrediens i pantry
så räcker det till alla recept, vi behöver alltså inte hålla koll på hur mycket vi har eller behöver av varje ingrediens.
OBS: Notera att den här uppgiften inte behöver recipe_db
alls.
Tips: För att ett recept ska kunna tillredas så måste de ingredienser som krävs vara en delmängd av de ingredienser som finns tillgängliga.
11.8.3 (5p)
Skriv en funktion add_recipe(recipe, database)
som lägger till receptet recipe
i receptdatabasen database
. Ett recept är en dict
med nycklarna "name"
och "ingredients"
.
Exempel
>>> add_recipe({'name': 'typ gröt', 'ingredients': ['havregryn', 'vatten']}, recipe_db)
>>> for k, v in recipe_db.items(): print(f'{k}: {v}')
kladdkaka: ['smör', 'socker', 'kakao', 'mjöl']
typ bröd: ['mjöl', 'vatten']
typ kaka: ['mjöl', 'socker', 'mjölk']
sockerkaka: ['ägg', 'socker', 'smör', 'mjöl']
pannkaka: ['ägg', 'socker', 'mjöl', 'mjölk']
mördegskakor: ['smör', 'socker', 'mjöl']
typ gröt: ['havregryn', 'vatten']
11.8.4 (5p)
Skriv en funktion add_ingredient(ingredient, recipe, database)
som tar två strängar och en receptdatabas som argument. Funktionen ska lägga till ingrediensen ingredient
i receptet recipe
i receptdatabasen database
.
Exempel
>>> add_ingredient('jäst', 'typ bröd', recipe_db)
>>> for k, v in recipe_db.items(): print(f'{k}: {v}')
kladdkaka: ['smör', 'socker', 'kakao', 'mjöl']
typ bröd: ['mjöl', 'vatten', 'jäst']
typ kaka: ['mjöl', 'socker', 'mjölk']
sockerkaka: ['ägg', 'socker', 'smör', 'mjöl']
pannkaka: ['ägg', 'socker', 'mjöl', 'mjölk']
mördegskakor: ['smör', 'socker', 'mjöl']
11.8.5 (30p)
Den här uppgiften har tidigare varit med på duggan.
Skriv en funktion possible_recipes(database, pantry)
som får en receptdatabas och en lista med som finns tillgängliga i “skafferiet” som argument och returnernar alla recept som kan bakas med dessa ingredienser. Alla ingredienserna i skafferiet måste inte användas.
Vi gör det förenklande antagandet att om vi har tillgång till en ingrediens i pantry
så räcker det till alla recept, vi behöver alltså inte hålla koll på hur mycket vi har eller behöver av varje ingrediens.
Exempel
Obs! Ordningen på resultatet måste inte matcha exemplen nedan.
|
|
Uppgift 11.9
Vi lagrar information om länder enligt nedan:
|
|
11.9.1 (5p)
Skriv en funktion get_highest_on_metric(countries, metric)
som tar data om länder enligt ovan och returnerar det land som har det högsta värdet på måttet metric
.
Exempel
>>> get_highest_on_metric(country_data, 'population')
'Germany'
>>> get_highest_on_metric(country_data, 'area')
'Sweden'
>>> get_highest_on_metric(country_data, 'gdp')
'Germany'
11.9.2 (5p)
Skriv en funktion get_metric_values(countries, metric)
som ska returnera en lista med alla värden av ett visst mått från data enligt formatet ovan.
Exempel
>>> get_metric_values(country_data, 'population')
[10452326, 83155031, 17475415, 56489800, 11521238]
>>> get_metric_values(country_data, 'area')
[450295, 357600, 41545, 132932, 30689]
>>> get_metric_values(country_data, 'gdp')
[622.8, 4880.4, 1095.4, 2698.3, 659.3]
11.9.3 (5p)
Skriv en funktion get_metric_mean(countries, metric)
som ska returnera medelvärdet av alla mått metric
.
Tips: Om man löst get_metric_values
kan man låta den göra större delen av jobbet.
Exempel
>>> get_metric_mean(country_data, 'population')
35818762.0
>>> get_metric_mean(country_data, 'area')
202612.2
>>> get_metric_mean(country_data, 'gdp')
1991.2400000000002
11.9.4 (5p)
Skriv en funktion add_country(country, data, year, dataset)
som tar en sträng country
, ett dictionary data
, ett år year
och ett dataset enligt ovan som argument. Funktionen ska lägga till landet country
med dess data data
i datasetet med 'data_year'
satt till year
. Om landet redan finns i datasetet ska inget göras.
Exempel
>>> add_country('France', {'population': 65505213, 'area': 643801, 'gdp': 3358.9}, 2021, country_data)
>>> for k, v in country_data.items(): print(f'{k}: {v}')
Sweden: {'population': 10452326, 'area': 450295, 'gdp': 622.8, 'data_year': 2021}
Germany: {'population': 83155031, 'area': 357600, 'gdp': 4880.4, 'data_year': 2020}
Netherlands: {'population': 17475415, 'area': 41545, 'gdp': 1095.4, 'data_year': 2021}
England: {'population': 56489800, 'area': 132932, 'gdp': 2698.3, 'data_year': 2021}
Belgium: {'population': 11521238, 'area': 30689, 'gdp': 659.3, 'data_year': 2021}
France: {'population': 65505213, 'area': 643801, 'gdp': 3358.9, 'data_year': 2021}
11.9.5 (5p)
Skriv en funktion update_country(country, data, year, dataset)
som tar en sträng country
, ett dictionary data
, ett heltal year
, och ett dataset enligt ovan som argument. Funktionen ska uppdatera landet country
med dess data data
i datasetet och sätta dess “data_year” till year
. Om landet inte finns i datasetet ska inget göras.
Exempel
>>> update_country('Germany', {'population': 83237124, 'area': 357600, 'gdp': 5237.2}, 2021, country_data)
>>> for k, v in country_data.items(): print(f'{k}: {v}')
Sweden: {'population': 10452326, 'area': 450295, 'gdp': 622.8, 'data_year': 2021}
Germany: {'population': 83237124, 'area': 357600, 'gdp': 5237.2, 'data_year': 2021}
Netherlands: {'population': 17475415, 'area': 41545, 'gdp': 1095.4, 'data_year': 2021}
England: {'population': 56489800, 'area': 132932, 'gdp': 2698.3, 'data_year': 2021}
Belgium: {'population': 11521238, 'area': 30689, 'gdp': 659.3, 'data_year': 2021}
11.9.6 (30p)
Den här uppgiften har tidigare varit med på duggan.
Skriv funktionen get_countries_over(countries, metric, val)
, där metric
säger vilket värde som ska hämtas, och val
är datavärdet som jämförs med. Funktionen ska returnera en lista med namnen på de länder där värdet för nyckeln är större än val
.
Tips: För att det ska vara lättare att som programmerare se skillnad mellan tal med många siffror så kan man i Python lägga in _
-tecken i heltalen. Dessa ignoreras vid beräkningar men kan göra det tydligare att läsa heltalsliteraler eftersom man kan gruppera siffrorna tre och tre. Se sista exemplet nedan där 20_000_000
är lika med 20000000
.
Exempel
|
|
Sidansvarig: Johan Falkenjack
Senast uppdaterad: 2025-08-05