Seite 3 von 3

Verfasst: Montag 11. Juli 2005, 09:15
von mawe
Hi!

Ich hab mal meine beiden Beiträge (4 und 6) benchmarktauglich gemacht ;)

Code: Alles auswählen

def format_number_4(number, comma=".", thousand=",", format="%.2f"):
    number = format % number
    minus = 0
    if number < 0:
        minus = 1
        number = abs(number)
    n = str(number).split(comma)
    n[0] = list(str(n[0]))[::-1]
    n[0] = comma.join(
            ["".join(n[0][i:i+3][::-1]) for i in
             range(0,len(n[0]),3)][::-1])
    if minus:
        return "%s%s" % ('-', thousand.join(n))
    else: return thousand.join(n)

def format_number_6(number, comma=".", thousand=",", format="%.2f"):
    """
    by mawe
    http://www.python-forum.de/viewtopic.php?p=20850#20850
    """
    number = format % number
    minus = 0
    if number < 0:
        minus = 1
        number = abs(number)
    n = str(number).split(comma)
    x = len(n[0]) % 3
    n[0] = "%s%s" % ("0" * (3-x), n[0])
    n[0] = comma.join([n[0][i:i+3]
              for i in range(0,len(n[0]),3)]).lstrip("0%s" % comma)
    if minus: return "%s%s" % ('-', thousand.join(n))
    else: return thousand.join(n)

Verfasst: Montag 11. Juli 2005, 09:57
von jens
Hab es aktualisiert. Nun ist der Test immer OK.

Hier die neuen Werte:
0 0.953s
0b 0.687s
1 1.235s
2 1.500s
3 1.406s
4 1.281s
5 0.766s
6 1.015s
format_numer_locale 1.828s

Verfasst: Montag 11. Juli 2005, 10:39
von mawe
Hi!

Harry's Version kann man noch etwas beschleunigen (eigentlich jede Version), wenn man alles < 1000 gleich zurückgibt. Ich versteh auch die Zeile

Code: Alles auswählen

s = s and decChar + s or s 
nicht wirklich. Kann man nicht gleich

Code: Alles auswählen

s = decChar + (format % (abs(number) % 1))[2:]
schreiben?
Naja, hier mal das ganze:

Code: Alles auswählen

def format_number_5(number, format = "%.2f", decChar = ",", groupChar = ".", groupRange = 3):
    """
    by HarryH
    http://www.python-forum.de/viewtopic.php?p=20888#20888

    Convert to required format
    number =      number to convert
    format =      python string formatting (%),but only for the decimals
    decChar =     decimal char for the converted format
    groupChar =   group char for the converted format
    groupRange =  group range for the converted format

    For example:
    __formatter(1234567890.987, "%.2f", ",", ".", 3)
    ==> 1.234.567.890,99

    """
    if abs(number) < 1000:
        return (format % (number)).replace(".", decChar)
    else:
        base = int(abs(number))
        s = decChar + (format % (abs(number) % 1))[2:]
        while base:
            s = groupChar + str(base)[-groupRange:] + s
            base = int(base / 10**groupRange)
        return number < 0 and "-" + s[1:] or s[1:]
Gruß, mawe

re:

Verfasst: Montag 11. Juli 2005, 10:57
von HarryH
Hi mawe,

Danke für deine Anregungen!

Erst alles > 1000 zurückzugeben ist bestimmt eine Verbesserung. Ich würde es aber, passend zu meinem Code, so machen:

Code: Alles auswählen

if abs(number) < 10**groupRange:
Es ist nämlich wichtig die Gruppierungsgröße mit einzubeziehen.

Der Sinn folgender der Zeile

Code: Alles auswählen

s = s and decChar + s or s
läßt sich leicht herausfinden wenn man 'format="%i"' an die Funktion übergibt. Ohne diese Zeile würde das Trennzeichen nämlich unnötigerweise hinzugefügt werden.

Verfasst: Montag 11. Juli 2005, 11:00
von jens
Hab's jetzt in dieser Version getestet:

Code: Alles auswählen

def format_number_5(number, format = "%.2f", decChar = ",", groupChar = ".", groupRange = 3):
    """
    by HarryH & mawe
    http://www.python-forum.de/viewtopic.php?p=20943#20943

    Convert to required format
    number =      number to convert
    format =      python string formatting (%),but only for the decimals
    decChar =     decimal char for the converted format
    groupChar =   group char for the converted format
    groupRange =  group range for the converted format

    For example:
    __formatter(1234567890.987, "%.2f", ",", ".", 3)
    ==> 1.234.567.890,99

    """
    if abs(number) < 10**groupRange:
        return (format % (number)).replace(".", decChar)
    else:
        base = int(abs(number))
        s = (format % (abs(number) % 1))[2:]
        s = s and decChar + s or s
        while base:
            s = groupChar + str(base)[-groupRange:] + s
            base = int(base / 10**groupRange)
        return number < 0 and "-" + s[1:] or s[1:]

Code: Alles auswählen

0 0.953s
0b 0.703s
1 1.266s
2 1.500s
3 1.422s
4 1.297s
5 0.687s
6 1.032s
format_numer_locale 1.843s
Wobei ich ja denke, das die Angabe von groupRange sinnlos ist, denn welche andere zahl außer drei wäre sinnvoll???

Verfasst: Montag 11. Juli 2005, 11:23
von cime
mawe hat geschrieben:Hi!

Harry's Version kann man noch etwas beschleunigen (eigentlich jede Version), wenn man alles < 1000 gleich zurückgibt. Ich versteh auch die Zeile
gute idee, hab meine gleich ma umgeändert ...

Code: Alles auswählen

import string

def format_number_0(number,format="%0.2f",comma=",",thousand=".",grouplength=3):
    if abs(number) < 10**grouplength: 
        return (format % (number)).replace(".", comma) 
    if number<0:
         vorzeichen="-"
         number=-number
    else:
        vorzeichen=""
    if format.endswith("f"):
        hinter_komma=string.split(format % number,".")[1]
        full_string=comma+hinter_komma
    elif format.endswith("i"):
        full_string=""
    number=int(number)
    x=1
    while (10**grouplength)**x<=number:
        full_string=thousand+str(number%((10**grouplength)**x))[0:grouplength]+full_string
        x+=1
    full_string=vorzeichen+str(number/((10**grouplength)**(x-1)))+full_string
    return full_string

#----------------------------------------------------------------------

def format_number_0b(number,format="%0.2f",comma=",",thousand=".",grouplength=3):
    if abs(number) < 10**grouplength: 
        return (format % (number)).replace(".", comma) 
    if number<0:
         vorzeichen="-"
         number=-number
    else:
        vorzeichen=""

    vor_komma,hinter_komma=string.split(format % number,".")
    add=0
    for i in range(grouplength,len(vor_komma),grouplength):
        vor_komma=vor_komma[0:-(i+add)]+thousand+vor_komma[-(i+add):]
    return vor_komma+comma+hinter_komma

wär übrigens ma dafür, dass wir uns auf eine Möglichkeit einigen und die optimieren bzw. uns auf mehrere einigen und diese verbinden und optimieren ...

Verfasst: Montag 11. Juli 2005, 11:32
von cime
cime hat geschrieben:wär übrigens ma dafür, dass wir uns auf eine Möglichkeit einigen und die optimieren bzw. uns auf mehrere einigen und diese verbinden und optimieren ...
um ma nen anfang damit zu machen hab ich gleich ma unsere zwei schnellsten getestet:

Code: Alles auswählen

import string


#----------------------------------------------------------------------

def format_number_0b(number,format="%0.2f",comma=",",thousand=".",grouplength=3):
    if abs(number) < 10**grouplength: 
        return (format % (number)).replace(".", comma) 
    if number<0:
         vorzeichen="-"
         number=-number
    else:
        vorzeichen=""

    vor_komma,hinter_komma=string.split(format % number,".")
    add=0
    for i in range(grouplength,len(vor_komma),grouplength):
        vor_komma=vor_komma[0:-(i+add)]+thousand+vor_komma[-(i+add):]
    return vor_komma+comma+hinter_komma


#----------------------------------------------------------------------


def format_number_5(number, format = "%.2f", decChar = ",", groupChar = ".", groupRange = 3): 
    """ 
    by HarryH & mawe 
    http://www.python-forum.de/viewtopic.php?p=20943#20943 

    Convert to required format 
    number =      number to convert 
    format =      python string formatting (%),but only for the decimals 
    decChar =     decimal char for the converted format 
    groupChar =   group char for the converted format 
    groupRange =  group range for the converted format 

    For example: 
    __formatter(1234567890.987, "%.2f", ",", ".", 3) 
    ==> 1.234.567.890,99 

    """ 
    if abs(number) < 10**groupRange: 
        return (format % (number)).replace(".", decChar) 
    else: 
        base = int(abs(number)) 
        s = (format % (abs(number) % 1))[2:] 
        s = s and decChar + s or s 
        while base: 
            s = groupChar + str(base)[-groupRange:] + s 
            base = int(base / 10**groupRange) 
        return number < 0 and "-" + s[1:] or s[1:] 

if __name__ == "__main__": 
    # Testen welche Funktion schneller ist 

    import time 

    zahlen = ( 
      66, 
      1, 
      2, 
      3.4, 
      -5.678, 
      612345, 
      612345.555, 
      987654321.067 
    )

    anz=100000
    for x in range(2):

        begin = time.time()

        for i in range(anz): 
          for zahl in zahlen: 
             x = format_number_0b(zahl)

        print "0b:", time.time() - begin 
        print 

        begin = time.time() 

        for i in range(anz): 
          for zahl in zahlen: 
             x = format_number_5(zahl) 
              
        print "5:", time.time() - begin 
        print 
Ergebnis:

Code: Alles auswählen

0b: 9.78099989891

5: 10.390999794

0b: 9.81299996376

5: 10.375
EDIT by mawe: Python tags korrigiert

re:

Verfasst: Montag 11. Juli 2005, 11:51
von HarryH
Hi,

cime's Version müßte nochmals überarbeitet werden. Sie funktioniert z.B. nicht bei folgenden Zahlen: -612345.555, 9876543210.067 und ebenfalls nicht bei natürlichen Zahlen >= 10**grouplength.

Verfasst: Montag 11. Juli 2005, 15:42
von cime
thx, harry: prob gelöst:

hier auch gleich nochma ein geschwindigkeitsvergleich:

Code: Alles auswählen

# -*- coding: cp1252 -*-
#format_number.py
import string


#----------------------------------------------------------------------

def format_number_0b(number,format="%0.2f",comma=",",thousand=".",grouplength=3):
    if abs(number) < 10**grouplength: 
        return (format % (number)).replace(".", comma)
    if format[-1]=="f":
        vor_komma,hinter_komma=string.split(format % number,".")
    else:
        vor_komma=format % number
        comma=""
        hinter_komma=""
    #Hier
    anz_leer=0
    for i in vor_komma:
        if i==" ":
            anz_leer+=1
        else:
            break
    vor_komma=vor_komma[anz_leer:]
    #bis hier
        
    len_vor_komma=len(vor_komma)
    for i in range(grouplength,len_vor_komma+(len_vor_komma-1)/(grouplength+1)-(number<0),grouplength+1):
        vor_komma=vor_komma[0:-(i)]+thousand+vor_komma[-(i):]
    return anz_leer*" "+vor_komma+comma+hinter_komma


#----------------------------------------------------------------------


def format_number_5(number, format = "%.2f", decChar = ",", groupChar = ".", groupRange = 3): 
    """ 
    by HarryH & mawe 
    http://www.python-forum.de/viewtopic.php?p=20943#20943 

    Convert to required format 
    number =      number to convert 
    format =      python string formatting (%),but only for the decimals 
    decChar =     decimal char for the converted format 
    groupChar =   group char for the converted format 
    groupRange =  group range for the converted format 

    For example: 
    __formatter(1234567890.987, "%.2f", ",", ".", 3) 
    ==> 1.234.567.890,99 

    """ 
    if abs(number) < 10**groupRange: 
        return (format % (number)).replace(".", decChar) 
    else: 
        base = int(abs(number)) 
        s = (format % (abs(number) % 1))[2:]
        s = s and decChar + s or s
        while base:
            s = groupChar + str(base)[-groupRange:] + s 
            base = int(base / 10**groupRange)
        return number < 0 and "-" + s[1:] or s[1:] 

if __name__ == "__main__": 
    # Testen welche Funktion schneller ist 

    import time 

    zahlen = ( 
      66, 
      1, 
      2, 
      3.4, 
      -5.678,
      -123456789.348,
      612345, 
      612345.555, 
      987654321.067,
      8756832640,
      354,
      816523
    )

    formate = (
        "%.2f",
        "%30.3f",
        "%10i"
        )

    groups = (
        2,
        3,
        4,
        5
        )
    
    anz=100000
    for x in range(2):

        begin = time.time()

        for i in range(1000):
            for format in formate: 
              for zahl in zahlen:
                  for group in groups:
                     x = format_number_0b(zahl,format=format,grouplength=group)

        print "0b:", time.time() - begin 
        print 

        begin = time.time() 

        for i in range(1000):
            for format in formate: 
              for zahl in zahlen:
                 for group in groups:
                     x = format_number_5(zahl,format=format,groupRange=group)
              
        print "5:", time.time() - begin 
        print 
Ergebnis:

Code: Alles auswählen

0b: 2.5150001049

5: 2.03099989891

0b: 2.48399996758

5: 2.03100013733


PS: @harry: bei den Formaten "%30.3f","%10i" macht deins probs ...

EDIT by mawe: Smilies deaktiviert (cime, bitte schau Dir Deine Beiträge an bevor Du sie absendest ;) )

Verfasst: Montag 11. Juli 2005, 22:09
von Leonidas
Für alle die es interessiert: PythonWunschliste wurde repariert und funktioniert wieder einwandfrei.

Verfasst: Dienstag 12. Juli 2005, 05:52
von HarryH
Hi cime,
cime hat geschrieben: PS: @harry: bei den Formaten "%30.3f","%10i" macht deins probs ...
Ich weiß. Deswegen habe ich in den docstring zu meiner Funktion geschrieben, das die Formatierung nur für die Dezimalstellen gilt.

Code: Alles auswählen

format =      python string formatting (%),but only for the decimals 
Wer z.B. eine Einrückung vornehmen möchte kann ja die Rückgabe der Funktion zusätzlich mit "%20s" formatieren!

Verfasst: Dienstag 12. Juli 2005, 10:35
von cime
HarryH hat geschrieben:

Code: Alles auswählen

format =      python string formatting (%),but only for the decimals 
Wer z.B. eine Einrückung vornehmen möchte kann ja die Rückgabe der Funktion zusätzlich mit "%20s" formatieren!
wär vielleicht gut, wenn man so was noch einbaut (etwa so:)

Code: Alles auswählen

def format_number_5(number, format = "%.2f", decChar = ",", groupChar = ".", groupRange = 3): 
    """ 
    by HarryH & mawe 
    http://www.python-forum.de/viewtopic.php?p=20943#20943 

    Convert to required format 
    number =      number to convert 
    format =      python string formatting (%),but only for the decimals 
    decChar =     decimal char for the converted format 
    groupChar =   group char for the converted format 
    groupRange =  group range for the converted format 

    For example: 
    __formatter(1234567890.987, "%.2f", ",", ".", 3) 
    ==> 1.234.567.890,99 

    """ 
    if abs(number) < 10**groupRange: 
        return (format % (number)).replace(".", decChar) 
    else: 
        base = int(abs(number)) 
        s = (format % (abs(number) % 1))[2:]
        s = s and decChar + s or s
        while base:
            s = groupChar + str(base)[-groupRange:] + s 
            base = int(base / 10**groupRange)
        if format[1]!="." or format[1]!="0":
            if format.endswith("f"):
                new_format=string.split(format,".")[0]+"s"
            else:
                new_format=format[0:-1]+"s"
            return new_format%(number < 0 and "-" + s[1:] or s[1:])
        else:
            return number < 0 and "-" + s[1:] or s[1:] 

re:

Verfasst: Dienstag 12. Juli 2005, 13:00
von HarryH
Hallo,

Un hier meine Lösung mit kompletter Formatierung. Ist nur minimal langsamer als ohne.
Funktioniert hervorragend, zumindest nach meiner Feststellung. :D

Code: Alles auswählen

def __formatter(number, format = "%.2f", decChar = ",", groupChar = ".", groupRange = 3, format_divider = ["^%(0?)([-+# ]*\d*)(.*)"]):
    """
    Convert to required format
    number =         number to convert
    format =         python string formatting (%)
    decChar =        decimal char for the converted format
    groupChar =      group char for the converted format
    groupRange =     group range for the converted format
    format_divider = split the format for exact formatting ( => do not change!)

    For example:
    __formatter(1234567890.987, "%020.2f", ",", ".", 3)
    ==> 00001.234.567.890,99

    """
    if abs(number) < 10**groupRange:
        return (format % (number)).replace(".", decChar)
    else:
        # set formatting strings by first calling of this function
        if type(format_divider[0]) == str:
            result = re.findall(format_divider[0], format)[0]
            format_divider[0] = result[0], "%0" + result[1] + "s", "%" + result[2]
        zeros, base_format, tail_format = format_divider[0]
        # formatting the number
        base = int(abs(number))
        tail = (tail_format % (abs(number) % 1))[2:]
        tail = tail and decChar + tail or tail
        s = ""
        while base:
            s = groupChar + str(base)[-groupRange:] + s
            base = int(base / 10**groupRange)
        # return with left filled zeros
        if zeros == "0":
            return number < 0 and base_format % ("-" + (s[1:] + tail).zfill(int(base_format[1:-1])-1)) \
                    or base_format % ((s[1:] + tail).zfill(int(base_format[1:-1])))
        # return without left filled zeros
        else:
            return number < 0 and base_format % ("-" + s[1:] + tail) or base_format % (s[1:] + tail)

Verfasst: Mittwoch 13. Juli 2005, 07:54
von cime

Code: Alles auswählen

def format_number_0b(number,format="%0.2f",comma=",",thousand=".",grouplength=3):
    if abs(number) < 10**grouplength: 
        return (format % (number)).replace(".", comma)
    if format[-1]=="f":
        vor_komma,hinter_komma=(format % number).split(".",-1)
    else:
        vor_komma=format % number
        comma=""
        hinter_komma=""
    #Hier
    anz_leer=0
    for i in vor_komma:
        if i==" ":
            anz_leer+=1
        else:
            break
    vor_komma=vor_komma[anz_leer:]
    #bis hier

    len_vor_komma=len(vor_komma)
    for i in range(grouplength,len_vor_komma+(len_vor_komma-1)/(grouplength+1)-(number<0),grouplength+1):
        vor_komma=vor_komma[0:-(i)]+thousand+vor_komma[-(i):]
    return anz_leer*" "+vor_komma+comma+hinter_komma
hab meine noch ein wenig beschleunigt ... *g*

Edit (Leonidas): Smiley im Code.. weg damit.

Verfasst: Freitag 15. Juli 2005, 15:08
von jens
Bin etwas verwirrt... Deine Funktion geht eigentlich... Doch wenn ich es in einer Klasse packe, dann nicht mehr:

Code: Alles auswählen

class test:
    def formatter( number, format="%0.2f", comma=",", thousand=".", grouplength=3):
        """
        Formatierung für Zahlen
        s. http://www.python-forum.de/viewtopic.php?t=371
        """
        if abs(number) < 10**grouplength:
            return (format % (number)).replace(".", comma)
        if format[-1]=="f":
            vor_komma,hinter_komma=(format % number).split(".",-1)
        else:
            vor_komma=format % number
            comma=""
            hinter_komma=""
        #Hier
        anz_leer=0
        for i in vor_komma:
            if i==" ":
                anz_leer+=1
            else:
                break
        vor_komma=vor_komma[anz_leer:]
        #bis hier

        len_vor_komma=len(vor_komma)
        for i in range(grouplength,len_vor_komma+(len_vor_komma-1)/(grouplength+1)-(number<0),grouplength+1):
            vor_komma=vor_komma[0:-(i)]+thousand+vor_komma[-(i):]
        return anz_leer*" "+vor_komma+comma+hinter_komma

print test().formatter( 1028.328 )
Traceback (most recent call last):
File "number_formatter.py", line 33, in ?
print test().formatter( 1028.328 )
File "number_formatter.py", line 10, in formatter
if abs(number) < 10**grouplength:
AttributeError: test instance has no attribute '__abs__'

EDIT: Hat sich erledigt... Es fehlt natürlich das self :oops: