Seite 1 von 1

Ist so etwas effizient ?

Verfasst: Sonntag 7. April 2013, 19:16
von Goswin
Die folgende Funktion cutoff entfernt überflüssige Nullen am Ende einer Zahlenfolge und funktioniert auch richtig; nur werde ich den Eindruck nicht los, dass ich bei so vielen Umwandlungen und Funktionsaufrufen für so eine einfache Sache mit Kanonen auf Spatzen schieße.

Geht es wirklich nicht einfacher?

Code: Alles auswählen

from itertools import dropwhile

def cutoff(tpl):
   return tuple(reversed(
      tuple(dropwhile( lambda e:not e, reversed(tpl) ))
      ))

folge = (1,2,2,0,0,0)
print(cutoff(folge))  #(1,2,2)

Re: Ist so etwas effizient ?

Verfasst: Sonntag 7. April 2013, 19:45
von Sirius3
Das zweimalige elementweise Erstellen von Tupeln sieht ziemlich ineffizient aus.
Warum suchst Du nicht den Index des Elements, das ≠0 ist, und nutzt slicing.

Code: Alles auswählen

def cutoff(tpl):
    for i, y in enumerate(reversed(tpl)):
        if y:
            return tpl[:-i]
    return ()

Re: Ist so etwas effizient ?

Verfasst: Sonntag 7. April 2013, 21:28
von Goswin
@Sirius3:

Dein Vorschlag funktioniert nur, wenn auch wirklich überflüssige Nullen vorhanden sind. Wenn keine da sind, zum Beispiel bei tpl=(1,2,2) oder bei einem mehrmaligen Aufruf

Code: Alles auswählen

tpl = cutoff(tpl)
...
tpl = cutoff(tpl)
dann wird die leere Folge () zurückgegeben, was natürlich voll unerwünscht ist.

Man kann das natürlich wie folgt reparieren, aber sehr elegant sieht das dann nicht aus:

Code: Alles auswählen

def cutoff(tpl):
    tpl = tuple(tpl) + (0,)
    for i, y in enumerate(reversed(tpl)):
        if y:
            return tpl[:-i]
    return ()

Re: Ist so etwas effizient ?

Verfasst: Sonntag 7. April 2013, 22:07
von bwbg
Sirius' Funktion leicht abgewandelt:

Code: Alles auswählen

def cutoff(seq):
    for i, y in enumerate(reversed(seq)):
        if y: break
    return seq[0:len(seq) - i]
Grüße ... bwbg

Re: Ist so etwas effizient ?

Verfasst: Sonntag 7. April 2013, 22:15
von BlackJack
@bwbg: Das dürfte dafür jetzt Probleme mit einer leeren Sequenz haben, weil dann `i` nicht definiert ist. :-)

Re: Ist so etwas effizient ?

Verfasst: Sonntag 7. April 2013, 22:23
von bwbg
Mein Anwalt sagt, dass eine leere Sequenz nie Teil der Anforderung des OP gewesen ist. :mrgreen:

Ganz kostenlos und nicht ganz ernst gemeint liefere ich folgendes hinterher:

Code: Alles auswählen

def cutoff_for_almost_every_corner_case_you_may_think_about(seq):
    try:
        return cutoff(seq)
    except UnboundLocalError:
        return ()
Ich hoffe, das Internet wird irgendwann mal gelöscht. :roll:

Grüße ... bwbg

Re: Ist so etwas effizient ?

Verfasst: Sonntag 7. April 2013, 22:29
von xeike
Hier eine Lösung ohne reverse:

Code: Alles auswählen

while folge[-1] == 0:
    folge = folge[:-1]
Falls du auch noch leere Folgen brauchst, dann ist

Code: Alles auswählen

while folge and folge[-1] == 0:
ganz gut :lol:

Re: Ist so etwas effizient ?

Verfasst: Sonntag 7. April 2013, 22:40
von BlackJack
@xeike: Effizienzpreise gewinnt man damit aber nicht wenn für jedes Element was abgeschnitten wird, die Sequenz kopiert werden muss.

Re: Ist so etwas effizient ?

Verfasst: Sonntag 7. April 2013, 22:42
von bwbg
Da stellt sich die Frage nach der (Ausführungs-)Effizienz aber nicht mehr. Beim Slicing wird eine neue Sequenz erzeugt (sprich das passende kopiert) und dies geschieht in Deinem Beispiel in jedem Schleifendurchlauf.

Grüße ... bwbg

Edit: Zu spät. And now you have to say: "Ah, interesting"

Re: Ist so etwas effizient ?

Verfasst: Sonntag 7. April 2013, 22:54
von EyDu
Ach, eine lineares Problem in quadratischer Laufzeit zu lösen ist doch quasi optimal ;-)

@bwbg: Gibs doch zu: Du hast die nicht mit deinem Anwalt unterhalten, du wolltest nur nicht zugeben, dass du das i=0 vergessen hast:

Code: Alles auswählen

def cutoff(seq):
    i = 0
    for i, y in enumerate(reversed(seq)):
        if y: break
    return seq[0:len(seq) - i]

Re: Ist so etwas effizient ?

Verfasst: Sonntag 7. April 2013, 23:30
von xeike
Ach so, wenn es um Effizienz geht... :)

Code: Alles auswählen

def dingsbums(foo):
    i = 1
    while foo[-i] == 0:
        i = i + 1
    return foo[0:len(foo) - i + 1]

l = [1] + [0 for i in range(10000)]
timeit.default_timer() ; dingsbums(l) ; timeit.default_timer()
 
So, für den Rest ist es mir jetzt zu spät.

Xe

PS: Für wenig abzuschneidendes macht "dingsbums" das Rennen, für viel hingegen "cutoff".

Re: Ist so etwas effizient ?

Verfasst: Montag 8. April 2013, 19:41
von Goswin
:D Vielen Dank für alle eure Lösungsvorschläge. Es erstaunt mich immer wieder, wie oft man (oder zumindest ich) die einfachen Dinge übersehen kann.