Python & geneste lijsten

Pagina: 1
Acties:

Vraag


Acties:
  • 0 Henk 'm!

  • utopiaBe
  • Registratie: Maart 2009
  • Niet online
Mijn vraag
Ik ben grandioos de mist aan het ingaan met geneste lijsten en als beginner kom ik er niet uit.

Wat ik zou moeten bekomen is het gemiddelde van het j-de element uit de sublijsten (die niet even lang moeten zijn.

listAvgs([[1,2,3],[4,5],[6,7,8,9],[10]]) zou dan het resultaat van [(1+4+6+10)/4, (2+5+7)/3, (3+8)/2, 9/1] moeten geven, of [5.25,4.67,5.5,9.0]

Ik zit me echter blind te staren op wat ik heb en kan er maar niet doorheen kijken. Mijn opzet was:
1) sla de lengtes van elke rij op in lijst
2) vul vervolgens elke kolom aan met 0 waar niks staat (neutraal element kan dan mee in som)
3) nu kan je de som nemen over elke rij en dit opslaan in een lijst
4) loop over som en lengtes om tot je gemiddelden te komen

So far, so good... ware het niet dat ik op 1 vastloop. De lengte van de kolommen is niet complex, ik zie echter niet hoe je die van de rijen kan bekomen.

Transpose zou een noodoplossing zijn, ware het niet dat numpy in de hele cursus niet aan bod komt en dit dus zeker niet de bedoeling is. Dit is overigens geen taak. Ik probeer me door wat oefeningen te worstelen voor een aankomend examen.
...

Relevante software en hardware die ik gebruik:
Python 3.10.5 in Wing
...

Wat ik al gevonden of geprobeerd heb:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def listAvgs(lst):
    longest = longestSublist(lst) #deze functie geeft de lengte van de langste sublijst weer
    lengths = []
    sums = []
    total = 0
    #selecteer lengte voor alle RIJEN (nu dus kolommen)
    for row in lst:
        lengths.append(len(row))
    #Wanneer rijen niet zo lang zijn als langste sublijst -> vul aan met neutraal element voor som
    for i in range(0,len(lst)):
        while len(lst[i])<longest:
            lst[i].append(0)
    #Neem som van i-de element in rij 
    for i in range(0,len(lst)):
        for j in range(0,longest):
            total += lst[j][i]
        sums.append(total)
        total = 0
    print('sums: ', sums)
    print('lengths: ', lengths)
    for i in range(0,len(lengths)):
        sums[i] = sums[i]/lengths[i]
    return sums

print(listAvgs([[1,2,3],[4,5],[6,7,8,9],[10]]))

...

Alle reacties


Acties:
  • 0 Henk 'm!

  • thlst
  • Registratie: Januari 2016
  • Niet online
Aanvullen lijkt me geen goed idee.

Waarschijnlijk wil je bij deze opdracht Exceptions gebruiken. Zijn deze al behandeld?

Acties:
  • 0 Henk 'm!

  • utopiaBe
  • Registratie: Maart 2009
  • Niet online
Nee, is echt nog de basis. Exceptions dus nog niet gezien. Eigenlijk enkel de basisbewerkingen, functies, lijsten, tuples, strings & sets (geen numpy, zip, etc. dus). Het is net dat wat het geheel wat complexer maakt dan nodig... Vandaar ook dat ik aan dat aanvullen dacht. Loop je natuurlijk nog steeds aan tegen het feit dat je de lengte van de rijen niet zonder meer kan opvragen.

Wellicht is er dus een erg eenvoudige oplossing en zit ik me gewoon blind te staren op 'wat ik wel zou kunnen toepassen, maar niet mag'.

[ Voor 44% gewijzigd door utopiaBe op 30-12-2022 05:13 ]


Acties:
  • +5 Henk 'm!

  • Wolfboy
  • Registratie: Januari 2001
  • Niet online

Wolfboy

ubi dubium ibi libertas

Ik neem aan dat je nog geen libraries zoals collections enzo behandeld hebt dus we gaan het even zo eenvoudig mogelijk maken :)

Door iets meer in de loop te doen hoef je niet eerst de langste sublijst te vinden:
Python:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def listAvgs(lst):
    # Verzamel de totale som en de lengtes in deze lijsten
    totals = []
    lengths = []

    for sublist in lst:
        # Loop door de sublijst met een counter. Als je `enumerate` niet mag
        # gebruiken dan kan je ook gewoon een `i += 1` in de loop zetten
        for i, value in enumerate(sublist):
            # Als we nog geen lijst van lengte `i` gehad hebben
            if i >= len(totals):
                totals.append(0)
                lengths.append(0)

            totals[i] += value
            lengths[i] += 1

    # Bereken het gemiddelde voor alle getallen
    results = []
    for total, length in zip(totals, lengths):
        results.append(total / length)

    return results

print(listAvgs([[1,2,3],[4,5],[6,7,8,9],[10]]))


Maar we kunnen het natuurlijk ook omgekeerd doen door eerst door de sublijsten heen te lopen:
Python:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
def listAvgs(lst):
    # Maak een lijst voor de resultaten
    results = []

    # Loop van 0 tot we geen langere lijsten meer kunnen vinden
    i = 0
    while True:
        total = 0
        count = 0

        for sublist in lst:
            # Als de lijst lang genoeg is, voeg het getal dan toe aan `total`
            if len(sublist) > i:
                total += sublist[i]
                count += 1

        # Als er waarden zijn, voeg ze dan toe aan de resultaten. Als die er
        # niet zijn dan moeten we uit de loop springen zodat we niet oneindig
        # loopen.
        if count:
            results.append(total / count)
        else:
            break

        i += 1

    return results

print(listAvgs([[1,2,3],[4,5],[6,7,8,9],[10]]))

Blog [Stackoverflow] [LinkedIn]


Acties:
  • +2 Henk 'm!

  • Ben(V)
  • Registratie: December 2013
  • Laatst online: 12:08
Waarom zo ingewikkeld, python heeft daar de functies sum() en len() voor.
Zoiets dus:

code:
1
2
3
4
LongList = [[1,2,3],[4,5],[6,7,8,9],[10]]

for Sublist in LongList:
    print(sum(Sublist)/len(Sublist))

[ Voor 5% gewijzigd door Ben(V) op 30-12-2022 09:44 ]

All truth passes through three stages: First it is ridiculed, second it is violently opposed and third it is accepted as being self-evident.


Acties:
  • 0 Henk 'm!

  • MaNDaRK
  • Registratie: Oktober 2001
  • Laatst online: 07:18
[quote]Ben(V) schreef op vrijdag 30 december 2022 @ 09:42:
Waarom zo ingewikkeld, python heeft daar de functies sum() en len() voor.
Zoiets dus:

[code]
LongList = [[1,2,3],[4,5],[6,7,8,9],[10]]

for Sublist in LongList:
print(sum(Sublist)/len(Sublist))
[/code]
[/quote]
Dit is inderdaad een mooie oplossing.

Of moet de ts alles zelf uitrekenen met geneste loops?
beter lezen.

Acties:
  • 0 Henk 'm!

  • eheijnen
  • Registratie: Juli 2008
  • Niet online
@Ben(V), @MaNDaRK
Vind de uitleg van @Wolfboy eigenlijk juist goed en helemaal niet overbodig.

Kan TS eens zien hoe en waarom het werkt. En deze uitleg kan in andere scenarios nog wel eens van pas komen...

En snapt hij ook meteen hoe de SUM functie werkt die BenV demonstreert.
Ook een een goed voorbeeld trouwens om te laten zien hoe het compacter kan in dit geval.

Wie du mir, so ich dir.


Acties:
  • +2 Henk 'm!

  • Wolfboy
  • Registratie: Januari 2001
  • Niet online

Wolfboy

ubi dubium ibi libertas

Ben(V) schreef op vrijdag 30 december 2022 @ 09:42:
Waarom zo ingewikkeld, python heeft daar de functies sum() en len() voor.
Zoiets dus:

code:
1
2
3
4
LongList = [[1,2,3],[4,5],[6,7,8,9],[10]]

for Sublist in LongList:
    print(sum(Sublist)/len(Sublist))
Die klopt alleen totaal niet :P
Het gaat om de som van de getransponeerde versies van de sublijsten.

Blog [Stackoverflow] [LinkedIn]


Acties:
  • 0 Henk 'm!

  • utopiaBe
  • Registratie: Maart 2009
  • Niet online
@Wolfboy: dankjewel! Dit verheldert inderdaad een hoop. Ook de 2 uitwerkingen naast mekaar...
Was duidelijk weer te ver aan het zoeken. Enumerate & zip was effectief nog niet gezien, maar kan me daar nu geen issue bij voorstellen. Bedoeling was vooral dat we geen collections, numpy, pandas,... gingen gebruiken.

@Ben(V) : thanks. Een esthetische oplossing, maar zoals hierboven gezegd neem je dan het gemiddelde van de lijsten (wat het probleem een stuk eenvoudiger maakt natuurlijk). Dat was waar ik wat op vast liep, aangezien deze sublists niet van gelijke lengte waren.

Acties:
  • 0 Henk 'm!

  • eheijnen
  • Registratie: Juli 2008
  • Niet online
Als je nog wat tijd over hebt dit weekend...een beetje leesvoer over "jagged arrays".
Wikipedia: Jagged array

Wie du mir, so ich dir.


Acties:
  • 0 Henk 'm!

  • Ben(V)
  • Registratie: December 2013
  • Laatst online: 12:08
Sorry mijn fout , dat krijg je als je te snel over de vraag heen leest.
Hier dan een compacte versie die wel goed is voor de fun

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from itertools import zip_longest

LongList = [[1,2,3],[4,5],[6,7,8,9],[10]]

# Compact
ListOfSums = [sum(ListToSum)/len(ListToSum) for ListToSum in [list(filter(None, transposed)) for transposed in zip_longest(*LongList)]] 
print(ListOfSums )

[# hetzelfde maar uitgesplitst
# eerst transponeer je de list of lists
transposed  = list(zip_longest(*LongList))
# Dat resulteerd in "None' waarden in de list, dus die moeten eruit, dat doe je met een filter
print (transposed)

# Dan halen we met een filter die "None" waarden eruit.
NoneRemoved = [list(filter(None, item)) for item in transposed]
print(NoneRemoved )

# En tenslotte maken we met sum() en len() een list van de gewesnte waarden
ListOfSums  = [sum(ListToSum)/len(ListToSum) for ListToSum in NoneRemoved]
print(ListOfSums)

[ Voor 22% gewijzigd door Ben(V) op 30-12-2022 17:42 ]

All truth passes through three stages: First it is ridiculed, second it is violently opposed and third it is accepted as being self-evident.


Acties:
  • 0 Henk 'm!

  • MaNDaRK
  • Registratie: Oktober 2001
  • Laatst online: 07:18
Wolfboy schreef op vrijdag 30 december 2022 @ 11:58:
[...]
Die klopt alleen totaal niet :P
Het gaat om de som van de getransponeerde versies van de sublijsten.
Je hebt helemaal gelijk! Het gaat om alle 'nth' nummers van de lijsten.

Dan heb ik hier een iets uitgebreidere versie, natuurlijk niet waterdicht als je lijst nullen bevat.
Python:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# orginele lijst
long_list = [[1, 2, 3], [4, 5], [6, 7, 8, 9], [10]]

# variabele voor de langste lijst:
longest = 0

# variabele voor de lijst lengte:
list_length = []

# variabele voor de resultaten:
result = []

# check welke sub_list het langste is:
for sub_list in long_list:
    if longest < len(sub_list):
        longest = len(sub_list)

# longest heeft nu de langste lijst:
# print(longest)

# sub_list eventueel aanvullen:
for sub_list in long_list:
    if len(sub_list) < longest:
        for _ in range(longest - len(sub_list)):
            sub_list.append(0)

# long_list heeft nu allemaal dezelfde lijst lengtes
# print(long_list)

# alles bij elkaar optellen:
for c in range(longest):
    temp = 0
    ll = 0
    for x in range(len(long_list)):
        # dit is natuurlijk niet waterdicht
        if long_list[x][c] != 0:
            ll += 1
        temp += long_list[x][c]
    
    # lijst lengte aanvullen:
    list_length.append(ll)
    
    # resultaat aanvullen:
    result.append(temp)

# berekenen resultaten:
for c in range(len(result)):
    result[c] = result[c] / list_length[c]

print(result)

Acties:
  • 0 Henk 'm!

  • utopiaBe
  • Registratie: Maart 2009
  • Niet online
Zo, en ik twijfelde nog om deze vraag initieel op het forum te gooien. Veel bijgeleerd, ook van de oplossingen die zaken gebruiken die ik nog niet zag (ondertussen ken ik die dan ook). Prachtig dit.

@eheijnen die jagged lists verken ik iig dieper. Met wat extra oefenen krijg ik dit wel onder de knie ;-). Door omstandigheden wat lessen moeten missen, maar uiteindelijk is het een kwestie van oefenen natuurlijk. Loopt ook vrij vlot, behalve deze dus...
Pagina: 1