die x grössten und kleinsten Werte aus Liste entfernen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
winnitouch
User
Beiträge: 21
Registriert: Montag 25. März 2019, 22:33

Hallo zusammen,

habe aktuell folgendes Problem.
Ich hab 2 Listen. Die erste Liste enthält Kontostände. Also zum Beispiel so:
[500, 700, 800, 650, 1000, 1500, 2400, 1750, 1800, 1900]

Daraus generiere ich eine zweite Liste, welche gemäss der Kontostandsliste den Gewinn/Verlust ermittelt, also wäre das so:
[500, 200, 100, -150, 350, 500, 900, -650, 50, 100]

Nun möchte ich die x (am besten beliebig einstellbar via Input zum Beispiel) grössten und kleinsten Werte aus der Gewinn/Verlust Liste entfernen und entsprechend eine korrekte, neue Kontostandsliste bauen.

Nun, wenn man für x einen festen Wert annimmt, dann hab ich eine (ziemlich) unelegante Lösung.

Mal angenommen, man nimmt für x = 2 an, dann lass ich 2 mal folgende Schleife für die max-Werte laufen, dann noch 2 mal für die Min werte, und dann bastel ich daraus eine neue Kontostandsliste. Das kommt mir aber maximal umständlich vor und es ist wie gesagt nicht dynamisch für x.

Code: Alles auswählen

    
#max-werte entfernen
for c in range(0,len(list_gewinn_verlust)):
    if list_gewinn_verlust[c] == max(list_gewinn_verlust):
         list_gewinn_verlust.pop(c)
         break
for c in range(0,len(list_gewinn_verlust)):
    if list_gewinn_verlust[c] == max(list_gewinn_verlust):
         list_gewinn_verlust.pop(c)
         break
         
#min-werte entfernen
for c in range(0,len(list_gewinn_verlust)):
    if list_gewinn_verlust[c] == min(list_gewinn_verlust):
         list_gewinn_verlust.pop(c)
         break
for c in range(0,len(list_gewinn_verlust)):
    if list_gewinn_verlust[c] == min(list_gewinn_verlust):
         list_gewinn_verlust.pop(c)
         break
Hat mir jemand eine elegante Lösung für das Problem mit dynamisch möglichem x?

Gruss
Sirius3
User
Beiträge: 18270
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn man etwas mehrfach wiederholen will, benutzt man eine Schleife, wie Du es ja schon tust.
Das was Du tust ist sehr ineffizient, weil Du für jedes Element neu den Maximalwert berechnest.

Eine Schleife läßt sich auch durch remove ersetzen:

Code: Alles auswählen

list_gewinn_verlust.remove(max(list_gewinn_verlust))
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

So zb:

Code: Alles auswählen

import operator
kontostand = [500, 700, 800, 650, 1000, 1500, 2400, 1750, 1800, 1900]

margin = 2 
tagged = sorted([(v, i) for i, v in enumerate(kontostand)])
clipped = [v for v, _ in sorted(tagged[margin:-margin], key=operator.itemgetter(1))]
print(clipped)
Benutzeravatar
snafu
User
Beiträge: 6866
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Ich würde das wohl so machen:

Code: Alles auswählen

sorted(gewinn_verlust)[x:-x]
Damit wird die Liste nach Größe sortiert. Anschließend werden die Werte ab dem x-ten Element geliefert und es wird beim x-letzten Wert gestoppt. Wenn x=2 ist, dann erhälst du also alles ab dem zweiten Element bis zum vorvorletzten Element.
Benutzeravatar
kbr
User
Beiträge: 1508
Registriert: Mittwoch 15. Oktober 2008, 09:27

@snafu: Das musst Du schon so machen wie __deets__, wenn nach entfernen der Extrema die ursprüngliche Reihenfolge der verbleibenden Elemente wieder hergestellt werden soll.
Benutzeravatar
snafu
User
Beiträge: 6866
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Dann könnte man sich bei meinem Ansatz das sortierte Ergebnis merken und anschließend das Original durchlaufen:

Code: Alles auswählen

relevant = set(sorted(gewinn_verlust)[x:-x])
print([wert for wert in gewinn_verlust if wert in relevant])
Benutzeravatar
__blackjack__
User
Beiträge: 14040
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@snafu: Da kann dann aber mehr entfernt werden als 2x Werte. Im Extremfall hat man am Ende sogar eine komplett leere Liste.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Mehr entfernt habe ich jetzt nicht so gesehen, aber zu viele beibehalten, wie dieses Beispiel schoen illustriert:

Code: Alles auswählen

x = 2
gewinn_verlust = [10]*10
relevant = sorted(gewinn_verlust)[x:-x]
ergebnis = [wert for wert in gewinn_verlust if wert in relevant]
print(gewinn_verlust == ergebnis) # True
Benutzeravatar
snafu
User
Beiträge: 6866
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

__blackjack__ hat geschrieben: Donnerstag 4. April 2019, 15:54 @snafu: Da kann dann aber mehr entfernt werden als 2x Werte. Im Extremfall hat man am Ende sogar eine komplett leere Liste.
Die Rede war ja nicht davon, dass x-mal zwei Elemente entfernt werden sollen, sondern halt die mit den x-größten und x-kleinsten Werten. Da wäre es IMHO nicht falsch, wenn bei doppelten Extremwerten zusätzliche Elemente rausfallen.
Benutzeravatar
snafu
User
Beiträge: 6866
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@__deets__: Da muss ich dir Recht geben. Den Fall hatte ich nicht bedacht. Hier ist dein Code robuster, wenn auch komplizierter.

Wobei natürlich die Frage ist, ob bei deinem 10er-Beispiel am Ende vielleicht besser eine leere Liste herauskommen sollte.
Zuletzt geändert von snafu am Donnerstag 4. April 2019, 16:12, insgesamt 1-mal geändert.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das vom TE dargestellte Verhalten ist das aber eben nicht. Er hat einen muehseligen Weg gefunden, aber es fliegt jeweils nur *ein* Element raus, und das dann x-mal. Und nicht beliebig oft mal.
Antworten