0
votes

Trying to practice my list comprehension, but at this point my code is looking a little (too) long per line length comprehension:

def sum_array(arr):
    return 0 if arr == None else sum(sorted(arr)[1:-1] for x in range(len(arr or [])-2)) 

Objective is to calculate sum of integers minus the min and max. If array is empty, None, or if only 1 element exists, the function should return 0.

I am receivingthe following

TypeError: unsupported operand type(s) for +: 'int' and 'list'

Please advise!

5
I don't see any list comprehension.. - Andrew Li
For a start, don't compare to None by equality; use identity. - jonrsharpe
One-liners are cool. But really, if you don't understand your own code, you may consider using multiple lines of code. - Loïc
I don't see why you're doing that for x in range(len(arr or [])-2) - Moses Koledoye
Worrying about arr being None is just a distraction. Assume that arr is at least a valid list of things you can add, and go from there. You aren't checking that arr doesn't contain strings, after all. - chepner

5 Answers

2
votes

Beautiful is better than ugly.

def sum_array(arr):
    if arr is None or len(arr) <= 1:
         return 0
    else:
         return sum(sorted(arr)[1:-1])
1
votes

Not sure why you need the for in the sum. It appears that x isn't used anywhere. This could be simplified to:

def sum_array(arr):
    return 0 if not arr else sum(sorted(arr)[1:-1])
0
votes

The easiest way to know where both the max and min is is to sort the list.

arr = sorted(arr)

arr[0] is the smallest, arr[-1] is the largest

So

if arr is None:
    return 0
else:
    return sum(sorted(arr)[1:-1])
0
votes

You get TypeError because you try to sum lists. Let me change your code a little bit:

 In[1]: arr = [1, 2, 3, 4, 5]
        [sorted(arr)[1:-1] for x in range(len(arr))]

Out[1]: [[2, 3, 4], [2, 3, 4], [2, 3, 4], [2, 3, 4], [2, 3, 4]]

I change your generator expression on list comprehension to show the idea. Really you generate a list on each implicit next call. A further consequence of this error is:

 In[2]: sum([[1],[2],[3]])       # will raise TypeError
Out[2]: TypeError: unsupported operand type(s) for +: 'int' and 'list'

 In[3]: sum([[1],[2],[3]], [])   # if you specify start, it will work
Out[3]: [1, 2, 3]

The signature of sum function is sum(iterable[, start]). Sums start and the items of an iterable from left to right and returns the total. start defaults to 0. The iterable‘s items are normally numbers, and the start value is not allowed to be a string. In fist case you really try to sum [1] + [2] + [3] + 0, and because + between list and int is not defined, that's why you get TypeError. In the second case [1] + [2] + [3] + [] this operation concatenates list and is perfectly valid.

And if you want review of your code and some feedback look at Stackexchange's CodeReview site.

You can try this, if you like one-liners. Here is also an assumption that a valid array is always instance of <class list>:

 In[4]: sum_array = lambda arr: sum(sorted(arr)[1:-1]) if isinstance(arr, list) else 0
        sum_array([4, 3, 8, 1, 7, 12, 5, 9])
Out[4]: 36

But it's not good practice!

0
votes

Here's a version which meets your requirements:

def sum_array(arr):
    return (None if len(arr) <= 1 else 0) if not arr else sum(sorted(arr)[1:-1])

cases = [[j + 1 for j in range(i)] for i in range(5)]

for c in cases:
    print(c, sum_array(c))

# Requirements: Objective is to calculate sum of integers minus the min and
# max. If array is empty, None, or if only 1 element exists, the function
# should return 0.
# [] None
# [1] 0
# [1, 2] 0
# [1, 2, 3] 2
# [1, 2, 3, 4] 5