0

Imagine I have

[1,2,[2,3],[[1,2],3]] as a string I need to calculate the total average like this:

0.25*(1+2+(0.5*(2+3))+(0.5*(0.5*(1+2)+3))) How could you detect all the parenthesis and do the average accordingly? The biggest problem is that initially is a string so first need to convert it somehow to values.

I have this:

def total(values):
    return sum(v if isinstance(v, int) else (1/len(v)) * total(v) for v in values)

But just works in case I have an array not a string. I cannot use a library

Hector Esteban
  • 1,011
  • 1
  • 14
  • 29
  • 1
    Does this answer your question? [Convert string representation of list to list](https://stackoverflow.com/questions/1894269/convert-string-representation-of-list-to-list) This works for list of lists too. – Ch3steR Apr 09 '20 at 12:50

3 Answers3

1

The result according to your formula is 1.9375. This you can get with the following more readable function. The problem of converting the list literal to a list is easily solved:

import ast

def avg(values):
    if not values:
        return 0
    if isinstance(values, list):
        return sum(map(avg, values)) / len(values)
    return values

>>> avg(ast.literal_eval('[1,2,[2,3],[[1,2],3]]'))
1.9375

You can, of course, force that function into a cryptic ternary one-liner:

def avg(vals):
    return sum(map(avg, vals)) / len(vals) if isinstance(vals, list) else vals
user2390182
  • 72,016
  • 6
  • 67
  • 89
0

(EDITED to add an option not requiring any library)

You can just combine your total() function (assuming that it is correct) with ast.literal_eval():

import ast


x = ast.literal_eval('[1,2,[2,3],[[1,2],3]]')
print(x)
# [1, 2, [2, 3], [[1, 2], 3]]

def total(values):
    return sum(v if isinstance(v, int) else (1/len(v)) * total(v) for v in values)


total(ast.literal_eval('[1,2,[2,3],[[1,2],3]]'))
# 7.75

If you cannot use a library, I guess you can still use eval(), which can be used essentially the same way as ast.literal_eval() except that it can run arbitrary Python code, so it is deemed to be unsafe.


It seems your total() function needs some fixing, i.e. you need to move the division by the number of elements outside of the call to sum(), e.g.:

def total(values):
    return sum(v if isinstance(v, int) else total(v) for v in values) / (len(values) if values else 1)
norok2
  • 25,683
  • 4
  • 73
  • 99
0

Edit 1: avoid using any additional libraries.

Edit 2: handle empty lists (interpret as 0).


You can get the list from the string with eval(). An elegant way to compute the nested mean is to define a recursive function:

def listmean(x):
    """recursively compute overall mean of nested lists"""
    if x == []:
        return 0
    elif type(x) == list:
        y = [listmean(x_i) for x_i in x]
        return sum(y) / len(y)
    else:
        return x

data = '[1, 2, [2, 3], [[1, 2], 3]]'
data = eval(data)  # evaluates string as Python expression (here: list)

listmean(data)

1.9375

Arne
  • 9,990
  • 2
  • 18
  • 28