Zorgmorduk
Zorgmorduk

Reputation: 1365

Ignore str in sum()

I have a list of lists containing predominantly numeric values. I need to find the highest value, determine the index of that list it contains, and sum up all values in that list.

I have this code that works fine:

results = [[213, 124, 100],
           [123.7, 444.6, 111, 12],
           [],
           [22, 11, 100, 2],
           [-1000]]

highest, row, total = -1, 0, 0
for a, b in enumerate(results):
    for i in b:
        if i > highest:
            highest = i
            row = a
            total = sum(b)

The problem is that I need to make sure, that the algorithm does not break if one of the values is a string. Is there a way to ignore strings in sum, or I'd need to iterate through b as well and check for strings?

Upvotes: 0

Views: 2205

Answers (2)

Padraic Cunningham
Padraic Cunningham

Reputation: 180441

If you want the index and the sublist with the highest single value:

results = [[213, 124, 100],
           [123.7, 444.6, 111, 12],
           [],
           [22, 11, 100, 2],
           [-1000]]

def try_mx(x):
    try:
        return max((i for i in x[1] if isinstance(i, (int, float))))
    except ValueError:
        return float("-inf")

mx_ind = max(enumerate(results), key=try_mx)


print(mx_ind)

Which will give you the index and the sublist:

 (1, [123.7, 444.6, 111, 12])

In your own code every time if i > highest is True you call sum, sum should only be called once per sublist if you found a higher value not every time you find a higher value.

You can use max again so you call sum only if the highest value is greater than the current highest, using python3 you can give max a default to catch your empty lists:

highest, row, total = float("-inf"), 0, 0
for a, b in enumerate(results):
    mx = max((i for i in b if isinstance(i, (int,float))), default=float("-inf"))
    if mx > highest:
        highest = mx
        row = a
        total = sum(b)

Upvotes: 1

Martijn Pieters
Martijn Pieters

Reputation: 1122372

You are already iterating through b; just check each value is not a string then. But yes, when using sum you need to filter out values that are strings too, use a generator expression:

for a, b in enumerate(results):
    for i in b:
        if not isinstance(i, str) and i > highest:
            highest = i
            row = a
            total = sum(i for i in b if not isinstance(i, str))

You could inverse the test and make sure the value is an int or float instead:

for a, b in enumerate(results):
    for i in b:
        if isinstance(i, (int, float)) and i > highest:
            highest = i
            row = a
            total = sum(i for i in b if isinstance(i, (int, float)))

It'd be much better if you could ensure the lists contained only numbers up front however:

highest, row, total = 0, 0, 0
filtered_results = [[i for i in b if isinstance(i, (int, float))] for b in results]
for a, b in enumerate(filtered_results):
    for i in b:
        if i > highest:
            highest = i
            row = a
            total = sum(b)

Upvotes: 1

Related Questions