Skip to content

S1Q1 · Double First and Last Elements in a List

⚡ Quick Reference

Function: double_ends(l: list) -> list

Core idea: prepend l[0] and append l[-1] to a copy of the list.

def double_ends(l: list) -> list:
    return [l[0]] + l + [l[-1]]

Key rules: - Returns a new list -do not modify the original - l[0] is the first element, l[-1] is the last - Works for any element type (ints, strings, etc.)


Problem Statement

Problem

Write a function double_ends(l) that returns a new list where the first element of l is duplicated at the beginning and the last element is duplicated at the end. The original list must not be modified.

Examples:

Input
[10, 20, 30]
Output
[10, 10, 20, 30, 30]
Input
['a', 'b', 'c']
Output
['a', 'a', 'b', 'c', 'c']
Input
[1, 2]
Output
[1, 1, 2, 2]

Understanding the problem

The result is simply the original list with one extra copy of the first element at the front and one extra copy of the last element at the back:

[10, 20, 30]
 ↓               ↓
[10] + [10, 20, 30] + [30]  =  [10, 10, 20, 30, 30]

List concatenation creates a new list

[l[0]] + l + [l[-1]] never modifies l -list + always returns a brand new list. This naturally satisfies the "do not modify the original" constraint.


Tracing the examples

Input [l[0]] l [l[-1]] Result
[10, 20, 30] [10] [10, 20, 30] [30] [10, 10, 20, 30, 30]
['a','b','c'] ['a'] ['a','b','c'] ['c'] ['a','a','b','c','c']
[1, 2] [1] [1, 2] [2] [1, 1, 2, 2]
[5,6,7,8] [5] [5,6,7,8] [8] [5,5,6,7,8,8]

Solution approaches

def double_ends(l: list) -> list:
    return [l[0]] + l + [l[-1]]

Wrap the first and last elements in single-element lists and concatenate. One line, no mutation.

def double_ends(l: list) -> list:
    result = list(l)          # make a copy so original is unchanged
    result.insert(0, l[0])    # prepend first element
    result.append(l[-1])      # append last element
    return result

Explicitly copy then mutate the copy. Makes the "don't modify original" requirement very visible.

def double_ends(l: list) -> list:
    return l[:1] + l + l[-1:]

l[:1] gives a list containing only the first element; l[-1:] gives a list containing only the last element. Slicing always returns a new list -clean and avoids wrapping in [].

double_ends = lambda l: [l[0]] + l + [l[-1]]

The entire function as a lambda. Useful when passing as an argument to map() or storing in a dispatch dictionary.


Key takeaways

01

[l[0]] + l + [l[-1]]

Wrapping a single element in [] makes it a list you can concatenate. l[0] alone can't be concatenated with a list -[l[0]] can.

02

List + never modifies in place

List concatenation with + always returns a new list. It's the safest way to satisfy "do not modify the original" -no explicit copying needed.

03

l[:1] vs [l[0]]

Both give a one-element list with the first item. l[:1] is slightly safer -it returns [] if the list is empty rather than raising an IndexError. For this problem either works since at least two elements are guaranteed.