Seite 1 von 2

Positive und negative Zahlen aus Liste separat addieren

Verfasst: Mittwoch 6. Februar 2013, 14:14
von lackschuh
Hallo

Was ist der einfachste Weg (so wenig Code wie möglich), damit ich aus einer Liste, welche mit positiven sowie negativen Werten gefüllt ist, die Summer aller positiven Zahlen und analog negative Zahlen anzeigen lassen kann?

Bsp:

Code: Alles auswählen

kassa = [150.00,-35.30,50.00,-5.50]
Ergebnis: 200.0 -40.8

Mit einer for-Schleife und zwei if-Anweisungen bekomm ich es gebacken, allerdings ist der Code dann 8 Zeilen lang...

Für Tipps bedank ich mich schon im Voraus 8)

Re: Positive und negative Zahlen aus Liste addieren

Verfasst: Mittwoch 6. Februar 2013, 14:30
von BlackJack
@lackschuh: Wofür braucht man da *zwei* ``if``-Anweisungen?

Re: Positive und negative Zahlen aus Liste addieren

Verfasst: Mittwoch 6. Februar 2013, 14:34
von bwbg

Code: Alles auswählen

sum(filter(lambda e: e > 0, kassa)), sum(filter(lambda e: e < 0, kassa)) # [1][2]
Nicht hübsch, liefert aber das gewünschte Ergebnis.

Grüße ... bwbg

[1] http://docs.python.org/3.3/library/functions.html#sum
[2] http://docs.python.org/3.3/library/func ... tml#filter

Re: Positive und negative Zahlen aus Liste addieren

Verfasst: Mittwoch 6. Februar 2013, 14:40
von mutetella

Code: Alles auswählen

>>> sum(i for i in kassa if i<0)
-40.799999999999997
>>> sum(i for i in kassa if i>0)
200.0
mutetella

Re: Positive und negative Zahlen aus Liste addieren

Verfasst: Mittwoch 6. Februar 2013, 14:42
von DasIch
Wenn man schon eine funktionale Lösung nutzt, sollte die zumindest in O(n) ablaufen.

Code: Alles auswählen

reduce(
    lambda (pos, neg), next: (pos + next, neg) if next >= 0 else (pos, neg + next),
    kassa,
    (0, 0)
)

Re: Positive und negative Zahlen aus Liste addieren

Verfasst: Mittwoch 6. Februar 2013, 14:44
von lackschuh
Tausend Dank

@BlackJack
Ich meinte if-else. Sry für das falsche Ausdrücken 8)

Re: Positive und negative Zahlen aus Liste addieren

Verfasst: Mittwoch 6. Februar 2013, 14:58
von EyDu
DasIch hat geschrieben:Wenn man schon eine funktionale Lösung nutzt, sollte die zumindest in O(n) ablaufen.
Du meinst so wie bisher alle genannten Lösungsvorschläge?

Re: Positive und negative Zahlen aus Liste addieren

Verfasst: Mittwoch 6. Februar 2013, 15:04
von snafu
EyDu hat geschrieben:
DasIch hat geschrieben:Wenn man schon eine funktionale Lösung nutzt, sollte die zumindest in O(n) ablaufen.
Du meinst so wie bisher alle genannten Lösungsvorschläge?
Die vorher genannten Vorschläge durchlaufen die Liste der Zahlen zweimal. Der Code von DasIch durchläuft sie nur einmal.

Ob das nicht wieder durch den Overhead an (Lambda-)Funktionsaufrufen aufgefressen wird, ist natürlich eine andere Sache...

Vielleicht zu dem Thema mal ein paar Infos: http://www.python.org/doc/essays/list2str/ (ich weiß aber nicht, wie aktuell die sind)

Re: Positive und negative Zahlen aus Liste addieren

Verfasst: Mittwoch 6. Februar 2013, 15:17
von cofi
snafu hat geschrieben:Die vorher genannten Vorschläge durchlaufen die Liste der Zahlen zweimal. Der Code von DasIch durchläuft sie nur einmal.
Nacheinander, macht O(2n) und 2n ∈ O(n).

Re: Positive und negative Zahlen aus Liste addieren

Verfasst: Mittwoch 6. Februar 2013, 15:39
von mutetella
Nachdem ich keine Ahnung habe, von was ihr da redet, habe ich das jetzt mal ausprobiert:

Code: Alles auswählen

import random
import time

kassa = range(100000) + range(-100000, 0)
random.shuffle(kassa)

def with_filter():
    t = time.time()
    sum(filter(lambda e: e > 0, kassa))
    sum(filter(lambda e: e < 0, kassa))
    return time.time() - t

def with_lc():
    t = time.time()
    sum(i for i in kassa if i<0)
    sum(i for i in kassa if i>0)
    return time.time() - t

def with_reduce():
    t = time.time()
    reduce(
        lambda (pos, neg), next: (pos + next, neg) if next >= 0 else (pos, neg + next),
        kassa,
        (0, 0)
    )
    return time.time() - t

Code: Alles auswählen

>>> with_filter()
0.10522699356079102
>>> with_lc()
0.066878795623779297
>>> with_reduce()
0.081995010375976562
mutetella

Re: Positive und negative Zahlen aus Liste separat addieren

Verfasst: Mittwoch 6. Februar 2013, 21:42
von derdon
Man muss übrigens nicht die O-Notation kennen, um das zu verstehen. Es reicht aus, wenn man weiß, dass filter unabhängig von den Parametern über die komplette Liste iterieren muss und sum ebenfalls immer über die komplette Liste iteriert. Wenn man das im Hinterkopf hat und das dann mit Lösungen vergleicht, die nur einmal über eine Liste iterieren, sollte einem auffallen, was davon wohl effizienter sein wird. Und das geht ohne Wissen über die Schreibweise O(n), O(2n) etc.

Re: Positive und negative Zahlen aus Liste separat addieren

Verfasst: Mittwoch 6. Februar 2013, 22:24
von Sirius3
Wenn man nur einmal über die Liste iteriert, hat das natürlich den Vorteil, dass man die Liste durch beliebige Iteratoren ersetzten kann.

Code: Alles auswählen

reduce(lambda (pos,neg),a: (pos+(a>0 and a),neg+(a<0 and a)), kassa, (0,0));

Re: Positive und negative Zahlen aus Liste separat addieren

Verfasst: Mittwoch 6. Februar 2013, 22:44
von mutetella
@derdon
Dass 2 mal iterieren mehr als 1 mal iterieren bedeutet ist mir wohl klar. Allerdings verstehe ich das Ergebnis dann nicht:
Dass die LC-Lösung schneller als die filter-Lösung ist, obwohl beide 2 x über die Liste gehen, liegt IMHO am zusätzlichen Funktionsaufruf den man sich bei der LC spart.
Dass allerdings die Lösung mit 'reduce()' trotz einmaliger Iteration nicht wesentlich schneller als LC ist, schaut für mich danach aus, dass nicht das einmalige oder zweimalige Iterieren, sondern eben der Funktionsaufruf entscheidend ist.

mutetella

Re: Positive und negative Zahlen aus Liste separat addieren

Verfasst: Mittwoch 6. Februar 2013, 22:57
von DasIch
@mutella Das liegt allerdings an der Implementation, PyPy liefert Ergebnisse die wesentlich näher sind an dem was man erwarten würde.

Code: Alles auswählen

% pypy
Python 2.7.2 (341e1e3821ff, Jun 07 2012, 15:42:54)
[PyPy 1.9.0 with GCC 4.2.1] on darwin
Type "help", "copyright", "credits" or "license" for more information.
And now for something completely different: ``it's a complete hack, but a very
minimal one (arigato)''
>>>> from foo import *
>>>> with_filter()
0.05291604995727539
>>>> with_lc()
0.05460405349731445
>>>> with_reduce()
0.02114582061767578

Re: Positive und negative Zahlen aus Liste addieren

Verfasst: Mittwoch 6. Februar 2013, 23:17
von /me
Die naheliegendste (und langsamste) Lösung will wohl sonst keiner präsentieren. :mrgreen:

Code: Alles auswählen

>>> kassa = [150.00,-35.30,50.00,-5.50]
>>> print map(sum, zip(*((0, item) if item < 0 else (item, 0) for item in kassa)))
[200.0, -40.8]

Re: Positive und negative Zahlen aus Liste separat addieren

Verfasst: Mittwoch 6. Februar 2013, 23:18
von Sirius3
DasIch hat geschrieben:PyPy liefert Ergebnisse die wesentlich näher sind an dem was man erwarten würde.
Die Frage ist, was würde man erwarten?

Wie viel Zeit kostet
1. das Vergleichen zweier Zahlen
2. das Durchlaufen einer Liste
3. das Erstellen von Tupeln
4. das Aufrufen einer Filter-Funktion

Ich hab mal nach Kosten sortiert, wobei ein Funktionsaufruf am teuersten ist.
Damit ist die with_filter-Methode weit abgeschlagen, da 1,2 und 4 jeweils zweifach
ausgeführt wird.
Stellt sich noch die Frage ist 1+2+3 oder 2*(1+2) größer?

Das pypy-Ergebnis verwundert mich.

Code: Alles auswählen

  mov ecx, count
  mov esi, offset kassa
  xor ebx,ebx
  xor edx,edx
@loop:
  lodsd
  or eax,eax
  jns @p
  add ebx,eax
  jmp @g
@p:
  add edx,eax
@g:
  loop @loop

Re: Positive und negative Zahlen aus Liste separat addieren

Verfasst: Mittwoch 6. Februar 2013, 23:44
von Sirius3
Warum unbedingt ein Einzeiler? Was die Anzahl der Zeichen betrifft,
Geschwindigkeit, usw:

Code: Alles auswählen

result = [0, 0]
for n in kassa:
    result[n<0] += n

Re: Positive und negative Zahlen aus Liste separat addieren

Verfasst: Donnerstag 7. Februar 2013, 00:13
von snafu
Sirius3 hat geschrieben:Warum unbedingt ein Einzeiler? Was die Anzahl der Zeichen betrifft,
Geschwindigkeit, usw:

Code: Alles auswählen

result = [0, 0]
for n in kassa:
    result[n<0] += n
Schon witzig, dass die Lösung ohne den ganzen "funktionalen Kram" die beste Performance zeigt. Zudem ist sie relativ kurz, wirkt elegant und auch nicht zu komplex. Damit ist sie für mich persönlich der Sieger. :)

Re: Positive und negative Zahlen aus Liste separat addieren

Verfasst: Donnerstag 7. Februar 2013, 08:21
von /me
Sirius3 hat geschrieben:

Code: Alles auswählen

result = [0, 0]
for n in kassa:
    result[n<0] += n
Das kann ja jeder. :D

Für mich ist es aber definitiv die übersichtlichste Lösung.

Re: Positive und negative Zahlen aus Liste separat addieren

Verfasst: Donnerstag 7. Februar 2013, 08:22
von mutetella
Sirius3 hat geschrieben:

Code: Alles auswählen

result = [0, 0]
for n in kassa:
    result[n<0] += n
Echt super schön! Da hat man gleich am morgen ein Lächeln im Gesicht... :)

mutetella