Set decimal numbers in a string list - Python

Asked

Viewed 442 times

1

I hope you can help me! I am on a project where I am creating some Graphics for a system that is used by people from various countries. Because of this, I created a function called formatC that, according to the language of the user’s country, the score (thousand and decimal markers) is changed.

And now, my problem is this: when plotting these my formatted values on the chart, I would like to standardize the number of decimals p all, that is, if the values are rounded to 2 decimal places, all must contain two decimal places. Example: 0.35, 0.20... And in python, 0.20 is represented as 0.2.

I’ll put down the example I have for you to run and test!

frequencies = [3, 1050, 2, 420, 60, 2]

freq = np.array(frequencies)

perc = freq/sum(freq)

perc2 = np.around(perc * 100, 2)

perc2

>array([ 0.2 , 68.31,  0.13, 27.33,  3.9 ,  0.13])


from babel.numbers import format_decimal
def formatC(values: list, culture_code: str = 'en-US'):

    """ Auxiliar function that returns a list of formatted numbers according to the given 
    culture code.
    
    :param culture_code: a str specifying the language used to set the decimal
    and big marks, defaults to 'en-US'
    :type culture_code: str
    :param values: a list of numbert to be formatted
    :type values: list
    """
    # Treating culture_code
    culture_code_treated = culture_code.replace('-', '_')
    # Creating empty list
    formatted_numbers = []
    # Appending the values formatted on the list created previously
    for i in range(len(values)):
        formatted_numbers.append(format_decimal(values[i], locale= culture_code_treated))
        
    # Returning the resulted list
    return(formatted_numbers)
test = formatC(perc2, 'en-US')
>['0.2', '68.31', '0.13', '27.33', '3.9', '0.13']
test2 = formatC(perc2, 'pt-BR')
>['0,2', '68,31', '0,13', '27,33', '3,9', '0,13']

And, from this last list quoted above, I want all numbers to have 2 decimal places, that is, 0.2/0.2 I want it to be 0.20/0.20 (msm thing p 3.9/3.9)!

Someone can help me?

  • Hi Helena- please don’t do this anymore - I stayed almost an hour explaining an answer to you and you erased the other question. Luckily, I was able to copy the text I wrote. Some people here are boring, and will come with "downvotes" and votes to close, even for perfectly answered questions. I’ll paste my answer back.

  • Hi, a thousand apologies! I am new here and did not know that other users could block my questions. I deleted because I thought ngm more could see it. I’m sorry again, and the question is better now?

  • yeah - that’s good. There are some users who have the role of moderators (I am an old user, with enough reputation, but I have no power of moderation) - from time to time I try to talk to moderators here because I think they have a culture that does not favor new users - I have seen questions that were negative and blocked here have 4 positive votes to be redone in stackoverflow in English.

1 answer

1

In fact, you’re doing it right already -

There is only "number with two squares after the comma" or in the form of a string. A "number" is a "number" - a quantity: "1", "1.0", "1,000" is the same number. (and even if you use the class "int" to put "1" and "1.0" in a float, Python continues to consider the same as equal: not only does the comparison " 1 == 1.0" be True, but [1.0] used as a key in a dictionary works interchangeably with 1. And this behavior is correct: number-by-number.

So there’s even the "Decimal" numeric type in Python: it can assure you that you’ll have numbers with 2 decimal places in your memory, and you’ll never have a rounding problem that will generate more decimal places. Now, using the float type, as you’re doing - even rounding with the Around or the native Python round, you can’t guarantee that the numbers will remain representable with two decimal places, no more broken values - because internally they’re stored in base 2, and some numbers just turn "periodic dizimas" when you change the basis of representation.

So while your application is running and processing the numbers- you use numbers. If you have any specific need for an algorithm to use only two decimal places, use the "Decimal" type, limiting the number of houses in the context - otherwise, leave the float types without rounding.

In the interfaces of your system with the outside world: either to print in the terminal, to write a file on disk - be it an Excel, a text file, a CSV, or generate an HTML page, with the numbers formatted for display - at this point you apply the "{:02f}". format(number) - You do not have to worry if when making an account the number is "1." or "1.00", "1.00000", because they are the same number. If it is not a numeric account, but needs the number as string ) for example, put it as the monetary representation - this is the "edge" - and you use the string.format at that point.

I saw your comment now - and I noticed that you want to standardize the numbers on a graph - so please add the code that generates the graph - is it with matplotlib? -and then we’ll explore how to format the numbers to be used as Labels in the graph - the above logic remains (it’s probably just passing the string-formatted list in the matplotlib call instead of the numbers as numbers)

In the example that is after you edit the question, returning the numbers in strings formatted with the number of decimals is trivial - if it is always the locale in English - a little more boring, if we have to take into account various locales.

I don’t know where in the format_decimal that you use in your code (the idea was to be able to run here, but without the "import"s, this is not possible). We can use the "format_string" function of the standard Python "locale" library -

And in addition, we will also use a Python syntax called "list comprehension" that reduces a three-line chunk and multiple function calls to just one.

So where have you got:

   formatted_numbers = []
    # Appending the values formatted on the list created previously
    for i in range(len(values)):
        formatted_numbers.append(format_decimal(values[i], locale= culture_code_treated))

With list comprhensions it is:

formatted_numbers = [format_decimal(value, locale=culture_code_treated) for value in values]

(Here, one uses the inline "for" - it executes, and executes the expression before it once for each element in the sequence given to the for is (the values variable. Apart from using this syntax, in Python we never need to do for i in range(Len(sequence)): value = sequence[i] ... - ofor in ython always goes through sequences - you don’t need to count the index, for the first thing inside the is to take the element in that index.

Good - but this is the same code that you had - I don’t know yet Which is the "format_decimal" function - and it may not accept the expression for numerical formatting, which we need - so let’s use locale.format_string - which accepts a format string in the syntax using "%" - the first form of Python string interpolation, inherited from the C language prinf. Before calling locale.format_string you have to configure locale, with the set_locale function:

import locale

def formatC(values, culture_code="en-US"):
   ...
   previous_locale = locale.get_locale(locale.LC_NUMERIC)
   locale.set_locale(locale.LC_NUMERIC, culture_code.replace("-", "_"))
   formatted = [locale.format_string("%.02f", value) for value in values]
   locale.set_locale(locale.LC_NUMERIC, previous_locale)
   return formatted

In the original question, you had added that function format_decimal that you are using, comes from the library babel. I consulted the library documentation (in fact, direct source code, which in the ipython environment can be seen only by placing the function followed by ??) - and, no, they do not accept an auxiliary form -only convert the numbers without rounding. But the standard library function locale Python, as I used above, accepts - step by string "%.02f" for her.

  • So@jsbueno... I can’t give you an example of the Graphics because they are part of a huge and internal class structure of the company... But what I need in essence is in my same question. I am looking for a way to get the result of using formatC (list of strings) and, when the number has a single decimal place, add a zero. I don’t know if I’ve been clear, or if I don’t understand your explanation

  • Yes - that’s answered in the end. My version of Formatc returns the list as you said it needs in the question, and respects the locale code (what Voce called "culture_code" - Babel also uses locales internally - these are international standards that come configured in the operating system, not even in Python)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.