Ask Your Question
1

Erasing some of the decimals in a list

asked 2020-11-26 19:11:43 +0100

Cyrille gravatar image

This is a nice table to the reserve of the to long decimals

A=[[10,10,10,10,10,10,10,10,10,10],[100,0,0,0,0,0,0,0,0,0],[11.1,11.1,11.1,11.1,11.1,11.1,11.1,11.1,11.1,0]
,[20,20,20,20,20,0,0,0,0,0],[50,25,12.5,6.25,3.125,1.56,0.78,0.39,0.19,0.09]]
t=table(A,header_row=["$1$","$2$","$3$","$4$","$5$","$6$","$7$","$8$","$9$","$10$"],header_column=["","Équi-Rep","Tout pour un","Un déshérité","Injuste pour 1/2","$5$","Injuste croissante"])
show(t)

I have tried to construct a function f(x)=round(x,2) and then to use A.map_apply(f) but this doesnot works since f(x)=round(x,2) generates an error. How shouild I do ?

edit retag flag offensive close merge delete

2 Answers

Sort by » oldest newest most voted
1

answered 2020-11-26 19:39:06 +0100

slelievre gravatar image

updated 2020-11-27 00:39:04 +0100

Here is a solution taking advantage of the following:

  • elements of RDF are represented with no trailing decimal zeros
  • matrices over RDF have a round method that can round to n decimal digits

There might be simpler ways, but hopefully this helps.

Define A as a list of lists:

sage: A = [[10] * 10, [100] + [0] * 9, [100/9] * 9 + [0]]
sage: A.extend([[20] * 5 + [0] * 5, [50/2**n for n in range(10)]])

Make a deep copy, so we can change it without changing A:

sage: D = deepcopy(A)

Round the rows with non-integer values:

sage: D[2] = list(matrix(RDF, A[2]).round(1)[0])
sage: D[4] = list(matrix(RDF, A[4]).round(2)[0])

Set table headers:

sage: hr = [f"${n}$" for n in (1 .. 10)]
sage: hc = ["", "Équirép", "Tout pour un", "Un déshérité"]
sage: hc += ["Injus moitié", "Injus croiss"]

Build the table:

sage: t = table(D, header_row=hr, header_column=hc)

The table in text mode:

sage: t
               | $1$    $2$    $3$    $4$    $5$    $6$    $7$    $8$    $9$    $10$
+--------------+------+------+------+------+------+------+------+------+------+------+
  Équirép      | 10     10     10     10     10     10     10     10     10     10
  Tout pour un | 100    0      0      0      0      0      0      0      0      0
  Un déshérité | 11.1   11.1   11.1   11.1   11.1   11.1   11.1   11.1   11.1   0.0
  Injus moitié | 20     20     20     20     20     0      0      0      0      0
  Injus croiss | 50.0   25.0   12.5   6.25   3.12   1.56   0.78   0.39   0.2    0.1

The latexed table:

sage: view(t)

Tableau de comparaison, version a

Simpler solution, inspired by the answer given by @dsejas.

Here A, hr, hc are as above.

Round only non-integer entries; adapt rounding precision to get 3 significant digits:

sage: f = lambda a: a if a in ZZ else round(a, 2 - floor(log(a, 10)))
sage: D = [[f(a) for a in r] for r in A]

Build the table:

sage: t = table(D, header_row=hr, header_column=hc)

The table in text mode:

sage: t
               | $1$    $2$    $3$    $4$    $5$    $6$    $7$     $8$     $9$     $10$
+--------------+------+------+------+------+------+------+-------+-------+-------+--------+
  Équirép      | 10     10     10     10     10     10     10      10      10      10
  Tout pour un | 100    0      0      0      0      0      0       0       0       0
  Un déshérité | 11.1   11.1   11.1   11.1   11.1   11.1   11.1    11.1    11.1    0
  Injus moitié | 20     20     20     20     20     0      0       0       0       0
  Injus croiss | 50     25     12.5   6.25   3.12   1.56   0.781   0.391   0.195   0.0977

The latexed table:

sage: view(t)

Tableau de comparaison, version b

edit flag offensive delete link more
1

answered 2020-11-26 20:07:30 +0100

dsejas gravatar image

updated 2020-11-27 01:39:36 +0100

Hello, @Cyrille! I believe that @slelievre has already given you a perfect solution for your problem, so i am just going to complement it with a few comments and alternatives for you, or any reader looking for the way to work with maps. However, I highly recommend using @slelievre's answer, which is way more efficient and elegant.

You cannot define f(x) = round(x, 2), because this is a symbolic definition, but round() is not a symbolic function. See the answer to this question for more details (I also made a similar mistake.) Remember that syntax like f(x) = x^2 is actually syntactic sugar defined by Sage for comfort. Instead, when you can't use that type of definitions, you should use a Python function definition:

def f(x):
    return round(x, 2)

Now, a similar approach to yours would be to use the map() function; this acts on the elements of a list. In your particular case, A is a list of lists, so you should define a function that takes a list (a row of your table) and returns a list with its elements rounded off (a new row of your table):

def f(row): # row is a row of your table "A" (automatically chosen by "map()")
    result = [] # this will be the new rounded off row
    for x in row:
        result.append(round(x, 2)) # this applies the "round()" function to every element of "row" and appends it to the new row
    return result

Now, you can apply this to your table A with this code:

A=[[10,10,10,10,10,10,10,10,10,10],[100,0,0,0,0,0,0,0,0,0],
     [11.1,11.1,11.1,11.1,11.1,11.1,11.1,11.1,11.1,0],
     [20,20,20,20,20,0,0,0,0,0],[50,25,12.5,6.25,3.125,1.56,0.78,0.39,0.19,0.09]]
temp = map(f, A)

Now temp is a Python map that will round your table elements. In order to trigger the process and obtain a new table (list of lists), you must write list(A), like in the following code:

t=table(list(temp),header_row="$1$","$2$","$3$","$4$","$5$","$6$","$7$","$8$","$9$","$10$"],
            header_column["","ÉquiRep","Tout pour un","Un déshérité","Injuste pour 1/2","$5$",
            "Injuste croissante"])
show(t)

Following @slelievre's answer, you can also use the following function:

 def f(row):
    result = []
    for x in row:
        result.append(RDF(x))
    return result

Once again, this syntax is necessary, since RDF() is not a symbolic function.

I hope this helps!

edit flag offensive delete link more

Comments

Note: you probably meant list(temp) rather than list(A).

slelievre gravatar imageslelievre ( 2020-11-26 21:19:28 +0100 )edit

Note: with A as in the question, a maybe simpler way to use round would be:

sage: f = lambda x: round(x, 2)
sage: D = [[f(x) for x in row] for row in A]

or if one likes using map:

sage: f = lambda x: round(x, 2)
sage: ff = lambda row: list(map(f, row))
sage: D = list(map(ff, A))

and then

sage: t = table(D, ...)
slelievre gravatar imageslelievre ( 2020-11-26 21:24:22 +0100 )edit

Opps, yes, I meant list(temp). I am correcting it now.

Also, thank you for the suggested code simplifications.

dsejas gravatar imagedsejas ( 2020-11-27 01:39:04 +0100 )edit

No problem. I like using comprehensions instead of initialising an empty list and appending in a for loop.

I find it more concise, elegant and expressive. It may be faster too.

Same for dictionaries, see Stack Overflow answer 64949287.

slelievre gravatar imageslelievre ( 2020-11-27 04:40:37 +0100 )edit

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools

1 follower

Stats

Asked: 2020-11-26 19:11:43 +0100

Seen: 780 times

Last updated: Nov 27 '20