liste mit 2er tupel subtrahieren

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.
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

The Peacemaker hat geschrieben:so ich werd mal ein bisschen präziser :)

also was ich genau will ist folgendes:

ich hab 2 liste mit 2er tupel.

die erste liste enthält als erstes element durchgehende indices und als zweites element float-werte.

die zweite liste ist genauso aufgebaut, enthält aber nur einen teil von der ersten liste.

bsp.:

liste1 = [(0, 0),(1, 0.5),(2,0.9),(3, 0.3),(4, 0.2),(5, 0.2),(6, 0.1)]
liste2 = [(1, 0.5),(3, 0.3),(5, 0.2),(6, 0.1)]



letztendlich will ist folgendes:

ich vergleiche beide listen miteinander, und wenn der index identisch ist, ziehe ich beide werte voneinander ab, und speichere die differenz in einer neuen liste, mit dem entsprechenden index.

findet man eine lücke in liste2, wird wieder subtrahiert, allerdings dann die letzte stelle wo man noch einen wert gefunden hat in liste2 vom aktuellen wert aus liste1.

bin schon wieder fleissig am rumtesten, aber ich bekomm immer "list index out of range" und "list indices must be integers" :(
Uhm...mach einfach mal ein Vorher/Nachher Beispiel.

Ein Tip Vorweg: Dictionary sollten helfen.
BlackJack

@The Peacemaker: Ich würde mich audax anschliessen: Bitte Beispiele, denn die Erklärung reicht auch für mich nicht aus.

Ich interpretiere es bisher so, dass Du ein Ergebnis haben möchstest, das sozusagen `liste2` mit Werten auffüllt indem Tupel wiederholt werden, für die es keinen Index in `liste1` gibt. Also ungefähr so:

Code: Alles auswählen

liste1 = [(0, 0.0), (1, 0.5), (2, 0.9), (3, 0.3), (4, 0.2), (5, 0.2), (6, 0.1)]
liste2 = [(0, 0.0), (1, 0.5), (1, 0.5), (3, 0.3), (3, 0.3), (5, 0.2), (6, 0.1)]
#         ???????              ^^^^^^              ^^^^^^
Die eingefügten Elemenete sind im Kommentar gekennzeichnet, beim ersten weiss ich nicht welche Werte da rein sollen.
Lonestar
User
Beiträge: 147
Registriert: Samstag 9. August 2008, 08:31

ohne nun jemanden ärgern zu wollen - meine 0815 Variante mit der einfachen Schleife ist da auch 'noch' möglich. Allerdings sieht man sofort was ich damit meine das ich immer noch in C-Syntax denke...

Das von BlackJack angesprochene Problem mit dem 1. dic in Liste1 (0,0) habe ich mal aussen vor gelassen

Code: Alles auswählen

a =  [(0, 0),(1, 0.5),(2,0.9),(3, 0.3),(4, 0.2),(5, 0.2),(6, 0.1)] 
b =  [(1, 0.5),(3, 0.3),(5, 0.2),(6, 0.1)] 
c = []
 
j = 0
for i in xrange(len(a)):
    c.append((i,a[i][1] - b[j][1]))
    if  a[i][0] == b[j][0]:
        j +=1
        
print c
ich versuche das gerade mal spasseshalber mit der Variante von BlackJack aber anscheinend habe ich die doch nicht so gut verstanden wie ich dachte...
The Peacemaker
User
Beiträge: 17
Registriert: Freitag 23. Mai 2008, 17:55

BlackJack hat geschrieben:@The Peacemaker: Ich würde mich audax anschliessen: Bitte Beispiele, denn die Erklärung reicht auch für mich nicht aus.

Ich interpretiere es bisher so, dass Du ein Ergebnis haben möchstest, das sozusagen `liste2` mit Werten auffüllt indem Tupel wiederholt werden, für die es keinen Index in `liste1` gibt. Also ungefähr so:

Code: Alles auswählen

liste1 = [(0, 0.0), (1, 0.5), (2, 0.9), (3, 0.3), (4, 0.2), (5, 0.2), (6, 0.1)]
liste2 = [(0, 0.0), (1, 0.5), (1, 0.5), (3, 0.3), (3, 0.3), (5, 0.2), (6, 0.1)]
#         ???????              ^^^^^^              ^^^^^^
Die eingefügten Elemenete sind im Kommentar gekennzeichnet, beim ersten weiss ich nicht welche Werte da rein sollen.

du hast das genau richtig verstanden :)



meint ihr es ist sinnvoller die 2. liste aufzufüllen, und dann erst die berechnung durchzuführen? drauf bin ich nämlich noch garnicht gekommen. ich hätte eher immer aufs vorgängerelement zugegriffen.
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

Also...so?

Code: Alles auswählen

liste1 = [(0, 0),(1, 0.5),(2,0.9),(3, 0.3),(4, 0.2),(5, 0.2),(6, 0.1)]
liste2 = [(1, 0.5),(3, 0.3),(5, 0.2),(6, 0.1)]


def transform(a, b):    
    j = 0
    for idx, val in a:
        current = b[j]
        if idx == current[0]:
            j += 1
            yield current
        yield idx, val

print list(transform(liste1, liste2))
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

Alternative mit Addition:

Code: Alles auswählen

def transform(a, b):    
    j = 0
    for idx, val in a:
        current = b[j]
        if idx == current[0]:
            j += 1
            yield idx, current[1] + val
        else:   
            yield idx, val

print list(transform(liste1, liste2))
The Peacemaker
User
Beiträge: 17
Registriert: Freitag 23. Mai 2008, 17:55

audax hat geschrieben:Also...so?

Code: Alles auswählen

liste1 = [(0, 0),(1, 0.5),(2,0.9),(3, 0.3),(4, 0.2),(5, 0.2),(6, 0.1)]
liste2 = [(1, 0.5),(3, 0.3),(5, 0.2),(6, 0.1)]


def transform(a, b):    
    j = 0
    for idx, val in a:
        current = b[j]
        if idx == current[0]:
            j += 1
            yield current
        yield idx, val

print list(transform(liste1, liste2))







setzt dieser ansatz dictonarys voraus?

ich habs mal auf meine listen angewandt, und ich erhalte leider "IndexError: list index out of range"




nachtrag:

muss es nicht "if idx == current[1]" heissen, wenn ich das 2. element bearbeiten will?

so bekomm ich nämnlich keinen indexfehler mehr.
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

Zu deinem Nachtrag:
Nein, der Index liegt doch im ersten Teil des Paares.

Und jetzt zeig eben deine Listen her..meine Güte.
BlackJack

Irgendwie ist mir die Aufgabe immer noch nicht klar. Und ich dachte schon, ich hätte sie verstanden. Soll die zweite Liste also mit Elementen aus der ersten aufgefüllt werden? Ich dachte es sollten Elemente in der zweiten *aus* der zweiten in Lücken wiederholt werden.

Vielleicht ist es ein wenig ungünstig, dass die Beispieldaten in beiden Listen die gleichen Werte zu den jeweiligen Indexen haben, so sieht man nicht wo die Ergebnisse her kommen sollen.

Nehmen wir mal das hier als Beispiel:

Code: Alles auswählen

    a = [(0, 4.7), (1, 1.1), (2, 1.3), (3, 3.1), (4, 0.0)]
    b = [(1, 2.3), (3, 4.2)]
Wie müsste jetzt ein aufgefülltes `b` aussehen und wo kämen diese Werte jeweils her?

Edit: Und was kann man über die Indexe sagen? Sind die wirklich in der ersten Liste immer aufsteigend? So lückenlos? Ist der Startindex bekannt?
The Peacemaker
User
Beiträge: 17
Registriert: Freitag 23. Mai 2008, 17:55

hab eben festgestellt dass mit meiner liste typ 1 was nicht stimmt.




das wäre ein bsp für ne liste typ 2:
[(53, 0.45018192137800001), (128, 0.34728442829700001), (129, 0.456179211084), (235, 0.36925521471700001), (482, 0.49590614351599999), (594, 0.56499722755699999), (603, 0.77058100829599996), (617, 0.75543537563499996), (626, 0.53642891059599995), (652, 0.68153047985500004),.......


nachtrag: fehler in liste 1 behoben.


die sieht so aus:

[(0, 0.0), (1, 0.0), (2, 0.0), (3, 0.0), (4, 0.0), (5, 0.0), (6, 0.0), (7, 0.0), (8, 0.0), (9, 0.0), (10, 0.0), (11, 0.0), (12, 0.0), (13, 0.0), (14, 0.0), (15, 0.0), (16, 0.0), (17, 0.0), (18, 0.0),
(19, 0.0), (20, 0.0), (21, 0.017494697371800001), (22, 0.053225052132200003), (23, 0.053225052132200003), (24, 0.083480231271999994), (25, 0.14087127320199999), (26, 0.14087127320199999), (27, 0.14087127320199999), (28, 0.14087127320199999), (29, 0.14087127320199999), (30, 0.200210336756), (31, 0.25113326636299999), (32, 0.19374222443299999), (33, 0.16348704529300001), (34, 0.16348704529300001), (35, 0.21146625670800001), (36, 0.26542000342599997), (37, 0.26542000342599997), (38, 0.26542000342599997), (39, 0.21449707381899999), (40, 0.21449707381899999), (41, 0.21449707381899999),.....





nachtrag2:

nochmal ne ausführliche erklärung: :)

(2. wert des jeweiligen tupels der 1. liste) - (2. wert des jeweiligen tupels der 2. liste)

der 1. wert (also der index) jedes tupels soll nicht geändert werden.


wenn man auf eine lücke stösst in der 2. liste, soll der vorgängerwert für die subtraktion verwendet werden. der vorgängwerwert kann auch weiter hinten liegen, je nachdem wie gross die lücke ist.

wenn ich zB in der 1. liste bei (5, 0.5) bin, es in liste 2 aber leider nur ein (3, 0.3) und ein (6, 0.1) gibt, soll er (5, 0.5) - (3, 0.3) = (5, 0.2) rechnen und das ergebis an eine neue liste anhängen.

ich hoffe es wurde einigermassen klar :)


nachtrag3:


ich glaube das größte problem ist, dass nicht immer ein erstes element in der 2. liste vorhanden ist. dann greift er quasi ins "leere"

da sollte er dann mit einer 0 rechnen.

ich werkel mal weiter, wenn sich was tut melde ich mich.
bin weiterhin für vorschläge dankbar.
BlackJack

Noch immer nicht ganz. Liste 2 fängt mit einer Lücke an, dass heisst es gibt keinen Vorgängerwert. Und nochmal die Frage: Welche garantierten Eigenschaften haben die Indexe in Liste 1? So wie das im Beispiel aussieht, ist das einfach nur der Index des Tupels in der Liste, also völlig überflüssige und redundante Information. Wenn dem so ist, bräuchte man die Liste nicht einmal anschauen um die fehlenden Werte in der zweiten zu "erfinden". Wenn die Frage mit dem Startwert für die erse Lücke geklärt wäre…
The Peacemaker
User
Beiträge: 17
Registriert: Freitag 23. Mai 2008, 17:55

BlackJack hat geschrieben:Noch immer nicht ganz. Liste 2 fängt mit einer Lücke an, dass heisst es gibt keinen Vorgängerwert. Und nochmal die Frage: Welche garantierten Eigenschaften haben die Indexe in Liste 1? So wie das im Beispiel aussieht, ist das einfach nur der Index des Tupels in der Liste, also völlig überflüssige und redundante Information. Wenn dem so ist, bräuchte man die Liste nicht einmal anschauen um die fehlenden Werte in der zweiten zu "erfinden". Wenn die Frage mit dem Startwert für die erse Lücke geklärt wäre…

Liste 2 KANN mit einer Lücke anfangen, muss aber nicht.


die indexe von liste 1 fangen bei 0 an und steigen dann einfach auf, je nachdem wie lang die liste ist die icheinlese. es gibt aber keine sprünge drin.

in der liste, in der nachher die ergebisse landen, sollten die indexe wieder drin sein, die brauch ich später bei der auswertung der ergebnisse.



ich mal euch mal ein bild:


Liste1: [(0,0), (1, 0.5), (2, 0.1 ), (3, 0.4), (4, 0.2 ), (5, 0.6)]
Liste 2: [ (1, 0,1), (5, 0.1)]
Liste mit Ergebnis: [(0,0), (1, 0.4), (2, 0), (3, 0.3), (4, 0.1), (5, 0.5)]
Lonestar
User
Beiträge: 147
Registriert: Samstag 9. August 2008, 08:31

die Startbedingung mit der 2. Liste machts irgendwie wesentlich komplizierter als es vorher war, aber nu kommt eine auf die schnelle zusammengeferkelte Variante die zumindest das problem mit deinem Beispiellisten nach deinen Anforderungen löst:

Code: Alles auswählen

a = [(0,0), (1, 0.5), (2, 0.1 ), (3, 0.4), (4, 0.2 ), (5, 0.6)] 
b = [ (1, 0.1), (5, 0.1)] 
c = []

def sub_list(a,b):
    print a[1], " - ", b[1]
    return (a[1] - b[1])

def comp_index(a,b):
    if a[0] == b[0]: 
        return True
    return False
    
    
j = 0
for i in xrange(len(a)):
    if j == 0:
        if comp_index( a[i], b[j]):
            c.append((i, sub_list(a[i], b[j])))
            j +=1
        else:    
            c.append((i, a[i][1]))
            if comp_index( a[i], b[j]):
                j +=1
    else:
        c.append((i, sub_list(a[i], b[j])))
        if  comp_index( a[i], b[j]):
            j +=1
print c
Wäre Liste 2 mit nem ordenltichen Startwert Versehen - in deinem Beispiel (0,0) könnte der ganze Rönz unter 'if j == 0:' wegfallen. Ich lass mich mal überraschen wie man das in ordentlichem Python löst

[edit]
aber mal was anderes - wozu brauchst du überhaupt den Index in dem Tupel? Wenn der Index immer mit dem Listenplatz übereinstimmt ist das doch wie BlackJack schon sagt redundant und eigentlich nicht mehr nötig.
[/edit]
The Peacemaker
User
Beiträge: 17
Registriert: Freitag 23. Mai 2008, 17:55

Lonestar hat geschrieben:
[edit]
aber mal was anderes - wozu brauchst du überhaupt den Index in dem Tupel? Wenn der Index immer mit dem Listenplatz übereinstimmt ist das doch wie BlackJack schon sagt redundant und eigentlich nicht mehr nötig.
[/edit]

naja... bei liste 2 hätte ich ja sonst nur zahlen aneinander gereiht. wie soll ich die dann dem entsprechenden wert aus liste 1 zuordnen?
BlackJack

@The Peacemaker: Und *noch einmal* die Frage: Was soll bei Lücken vor dem ersten Wert passieren? Es kann doch nicht so schwer sein diese Frage mal zu beantworten!? Wo kommt die (0,0) in Deinem Ergebnis her? Also insbesondere der zweite Wert. Sollen die Werte vor dem ersten Index einfach mit 0en versehen werden, oder braucht man dafür irgendwie die erste Liste?

Das gezeigte Ergebnis bekommt man jedenfalls so:

Code: Alles auswählen

from functools import partial
from itertools import imap
from operator import itemgetter, sub


def fill_gaps(data):
    last_index, last_value = (0, 0.0)
    for index, value in data:
        for dummy in xrange(last_index, index):
            yield last_value
        yield value
        last_index, last_value = index + 1, value


isecond = partial(imap, itemgetter(1))


def main():
    data_a = [(0, 0.0), (1, 0.5), (2, 0.1), (3, 0.4), (4, 0.2), (5, 0.6)]
    data_b = [(1, 0.1), (5, 0.1)]
    
    result = list(enumerate(imap(sub, isecond(data_a), fill_gaps(data_b))))
    print result
@Lonestar: Die beiden Funktionen sind etwas übertrieben, sogar in C wären sie das. Insbesondere `comp_index()` was eigentlich auch nur ein Einzeiler wäre:

Code: Alles auswählen

def comp_index(a, b):
    return a[0] == b[0]
BlackJack

@The Peacemaker: Aber in der *ersten* Liste sind die Indexe in den Tupeln einfach nur überflüssig. In meiner letzten Lösung entferne ich die vorher und füge sie hinterher wieder hinzu. Ist also nur zusätzliche Arbeit.
The Peacemaker
User
Beiträge: 17
Registriert: Freitag 23. Mai 2008, 17:55

BlackJack hat geschrieben:@The Peacemaker: Und *noch einmal* die Frage: Was soll bei Lücken vor dem ersten Wert passieren? Es kann doch nicht so schwer sein diese Frage mal zu beantworten!? Wo kommt die (0,0) in Deinem Ergebnis her? Also insbesondere der zweite Wert. Sollen die Werte vor dem ersten Index einfach mit 0en versehen werden, oder braucht man dafür irgendwie die erste Liste?

tut mir leid, das hab ich wohl beim editieren gelöscht.

ich dachte mir dass er da einfach ne 0 reinschreiben soll. das ist auch nicht so schlimm, da die ergebnisse erst interessant werden wenn sich in liste2 was tut.



eure ergebnisse funktionieren gut, vielen dank erstmal dafür. ich hab nur noch das problem dass eine meiner listen für liste2 "IndexError: list index out of range" produziert, ich bin noch dabei herauszufinden wieso.
Lonestar
User
Beiträge: 147
Registriert: Samstag 9. August 2008, 08:31

BlackJack hat geschrieben:
@Lonestar: Die beiden Funktionen sind etwas übertrieben, sogar in C wären sie das. Insbesondere `comp_index()` was eigentlich auch nur ein Einzeiler wäre:
ja, das die Funktionen hier übertrieben sind ist mir nu aber auch aufgefallen. Allerdings habe ich mir angewöhnt sobald ich eine Redundanz bei Berechnungen habe diese direkt in eine externe Funktion auszulagern. Sowas wurde bei mir einfach viel zu oft unglaublich unübersichtlich - und wenn ich mich dann mal entschliessen konnte etwas auszulagern hab ich schon öfters selber nicht mehr auf Anhieb ganz durchgeblickt...
So habe ich zwar ab und an einige Funktionen die man sich sparen könnte - aber es wird dadurch halt nicht wirklich schlechter lesbar.

Allerdings werde ich mich heute Abend mal bei Gelegenheit hinsetzen und mir mit Verstand ansehen wie es in python auch in schön geht - vor allem enumerate und map könnten mir das Leben glaube ich wesentlich erleichtern
abgdf

@Lonestar: Natürlich hätte ich auch mit der xrange()-Schleife gearbeitet, wenn es mehr als 2 Listen gewesen wären.

@audax: Natürlich verwende ich in Python auch Module, wenn es der einfachste Weg ist.
Dein Code ist auch doof. Ich hol' gleich meinen großen Bruder, und der wirft mit Sand.

@The Peacemaker: Erst wenn Dir klar ist, was Du ausdrücken willst, kann man das in Code umsetzen.

Gruß
yipyip
User
Beiträge: 418
Registriert: Samstag 12. Juli 2008, 01:18

Falls noch jemand daran interessiert ist (und ich das Problem richtig verstanden habe), hier meine Loesung:

Code: Alles auswählen

def sub_lists(ls1, ls2):

  default = 0
  idx = 0
  
  for x1, y1 in ls1:
    x2, y2 = ls2[idx]
    if x1 == x2:
      default = y2
      idx += 1

    yield x1, y1 - default


ls1 = [(0, 1), (1, 0.5), (2, 0.1 ), (3, 0.4), (4, 0.2 ), (5, 0.6)]
ls2 = [(1, 0.1), (5, 0.1)]

print list(sub_lists(ls1, ls2))
:wink:
yipyip
Antworten