1

A "pyschool" exercise :

"Define a function calls addFirstAndLast(x) that takes in a list of numbers and returns the sum of the first and last numbers."

Here is the best solution I have come up with. Is there a more elegant way to write this function that also only uses only built in functions?

def addFirstAndLast(x):
    sum_list = []
    if len(x) == 0:
        return 0
    elif len(x) == 1 :
        return int(x[0])
    elif len(x) > 1 :
        sum_list.append(x[0]) 
        sum_list.append(x[-1])
    return sum(sum_list)
1
  • 3
    return x[0] + x[-1] for the last case, There is no need to create a new list as sum_list and then apply sum() if you really have only 2 numbers to add. Commented May 31, 2015 at 11:57

4 Answers 4

2
>>> def addFirstAndLast(x):
...   return (x[0]+x[-1])/(1/len(x)+1) if x else 0
... 
>>> addFirstAndLast([])
0
>>> addFirstAndLast([1])
1
>>> addFirstAndLast([1,3])
4

Note 1 : only when the length of list is 1 the result of (1/len(x)+1) is 2 so you divide the sum of first and last elements by 2 else it divide by 1.

Note 2 : if you are in python 3 use // for division instead /.

Sign up to request clarification or add additional context in comments.

5 Comments

This handles all the test cases., great :)
Somewhat convoluted logic there... and shouldn't you be using // for integer division?
@PM2Ring In python 3 yes but in this case there is no need to that because OP has accepted the answer!
Answers on Stack Exchange sites are also for the benefit of future readers, not just the OP.
@PM2Ring Yes its true :)
2

Kasra's answer is a lot better but this is a slightly different way to go about it. Since x[0] is always returned if it exists, you can just check if x[-1] should be added too.

def firstAndLast(x):
    if x:
        value = x[0]
        if len(x)>1:
            value += x[-1]
        return value
    return 0

1 Comment

Your code is easier to understand than Kasra's, and doesn't perform 2 mysterious divisions.
0
def addFirstAndLast(x):
    if x:
        return sum(zip(*filter(lambda (i,s): i == 0 or i == len(x) - 1, enumerate(x)))[1])
    else:
        return 0

Enumerate elements in the list, filter, unzip and then return the sum.

Comments

0

Use extended slice notation, with max to handle an empty list.

for i in range(5):
    a = range(10, 10 + i)
    b = a[::max(1, len(a)-1)]
    print a, b, sum(b)

output

[] [] 0
[10] [10] 10
[10, 11] [10, 11] 21
[10, 11, 12] [10, 12] 22
[10, 11, 12, 13] [10, 13] 23

And here's a version that does it in a function.

def add_first_and_last(x):
    return sum(x[::max(1, len(x)-1)])

for i in range(5):
    a = range(10, 10 + i)
    print a, add_first_and_last(a)

output

[] 0
[10] 10
[10, 11] 21
[10, 11, 12] 22
[10, 11, 12, 13] 23

At Kasra's prompting I've done some timing tests of the main existing answers. I've also added a modified version of Peter's algorithm that's slightly faster.

from timeit import Timer

def addFirstAndLast_Sam(x):
    sum_list = []
    if len(x) == 0:
        return 0
    elif len(x) == 1 :
        return int(x[0])
    elif len(x) > 1 :
        sum_list.append(x[0]) 
        sum_list.append(x[-1])
    return sum(sum_list)

def add_first_and_last_PM2Ring_slow(x):
    return sum(x[::max(1, len(x)-1)])

def add_first_and_last_PM2Ring_fast(x):
    return x[0] + x[-1] if len(x) > 1 else x[0] if x else 0

def firstAndLast_Peter(x):
    if x:
        value = x[0]
        if len(x)>1:
            value += x[-1]
        return value
    return 0

def addFirstAndLast_Kasra(x):
    return (x[0] + x[-1]) // (1 // len(x) + 1) if x else 0

funcs = (
    add_first_and_last_PM2Ring_fast,
    firstAndLast_Peter,
    addFirstAndLast_Kasra,
    add_first_and_last_PM2Ring_slow,
    addFirstAndLast_Sam,
)

num = 10
lists = [range(10, 10 + i) for i in range(num + 1)]

def verify():
    ''' Verify that the functions actually perform as intended '''
    print 'Verifying...'
    for func in funcs:
        fname = func.func_name
        print '\n%s' % fname
        for a in lists:
            print a, func(a)

def time_test(loops, reps):
    ''' Print timing stats for all the functions '''
    print '\nTiming tests\nLoops = %d, Repetitions = %d' % (loops, reps)

    for func in funcs:
        fname = func.func_name
        print '\n%s' % fname
        setup = 'from __main__ import lists, %s' % fname
        t = Timer('[%s(a) for a in lists]' % fname, setup)
        r = t.repeat(reps, loops)
        r.sort()
        print r

verify()
time_test(loops=10000, reps=3)

output

Verifying...

add_first_and_last_PM2Ring_fast
[] 0
[10] 10
[10, 11] 21
[10, 11, 12] 22
[10, 11, 12, 13] 23
[10, 11, 12, 13, 14] 24
[10, 11, 12, 13, 14, 15] 25
[10, 11, 12, 13, 14, 15, 16] 26
[10, 11, 12, 13, 14, 15, 16, 17] 27
[10, 11, 12, 13, 14, 15, 16, 17, 18] 28
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19] 29

firstAndLast_Peter
[] 0
[10] 10
[10, 11] 21
[10, 11, 12] 22
[10, 11, 12, 13] 23
[10, 11, 12, 13, 14] 24
[10, 11, 12, 13, 14, 15] 25
[10, 11, 12, 13, 14, 15, 16] 26
[10, 11, 12, 13, 14, 15, 16, 17] 27
[10, 11, 12, 13, 14, 15, 16, 17, 18] 28
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19] 29

addFirstAndLast_Kasra
[] 0
[10] 10
[10, 11] 21
[10, 11, 12] 22
[10, 11, 12, 13] 23
[10, 11, 12, 13, 14] 24
[10, 11, 12, 13, 14, 15] 25
[10, 11, 12, 13, 14, 15, 16] 26
[10, 11, 12, 13, 14, 15, 16, 17] 27
[10, 11, 12, 13, 14, 15, 16, 17, 18] 28
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19] 29

add_first_and_last_PM2Ring_slow
[] 0
[10] 10
[10, 11] 21
[10, 11, 12] 22
[10, 11, 12, 13] 23
[10, 11, 12, 13, 14] 24
[10, 11, 12, 13, 14, 15] 25
[10, 11, 12, 13, 14, 15, 16] 26
[10, 11, 12, 13, 14, 15, 16, 17] 27
[10, 11, 12, 13, 14, 15, 16, 17, 18] 28
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19] 29

addFirstAndLast_Sam
[] 0
[10] 10
[10, 11] 21
[10, 11, 12] 22
[10, 11, 12, 13] 23
[10, 11, 12, 13, 14] 24
[10, 11, 12, 13, 14, 15] 25
[10, 11, 12, 13, 14, 15, 16] 26
[10, 11, 12, 13, 14, 15, 16, 17] 27
[10, 11, 12, 13, 14, 15, 16, 17, 18] 28
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19] 29

Timing tests
Loops = 10000, Repetitions = 3

add_first_and_last_PM2Ring_fast
[0.15383195877075195, 0.15486502647399902, 0.18578314781188965]

firstAndLast_Peter
[0.16625690460205078, 0.16726803779602051, 0.17240190505981445]

addFirstAndLast_Kasra
[0.19242000579833984, 0.19251012802124023, 0.21216797828674316]

add_first_and_last_PM2Ring_slow
[0.38388991355895996, 0.39070892333984375, 0.39607501029968262]

addFirstAndLast_Sam
[0.38914084434509277, 0.38966894149780273, 0.41235685348510742]

As you can see, my original code is definitely not the fastest, but it is the shortest. :)

2 Comments

There is no need to use sum and max and len for this simple task!!! you just make it very inefficient!
@Kasra: I agree that this approach is slower than yours. OTOH, Peter's code is faster than both of ours. I'll post some timing tests.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.