1

I have to write a function dup_elt(lst, pos=0) that takes a list and expands it by duplicating the element in position pos, returning a new list.

Examples:

dup_elt([1, 2, 100, 8])      # [1, 1, 2, 100, 8]
dup_elt([1, 2, 100, 8], 2)   # [1, 2, 100, 100, 8]
dup_elt([1, 2, 100, 8], 10)  # [1, 2, 100, 8]

Assuming that lst is a non-empty list and pos is a non-negative int. If lst[pos] does not exist, lst should be returned unchanged.

Optional argument: The argument specification pos=0 assigns the default value of 0 to pos if omitted from the function call.

I have done:

def dup_elt(lst,pos=0):
    return ([lst],(pos,pos)) 

However, that doesn't duplicate the list item.

2
  • This is pretty obviously a homework problem, and your attempt does not really show any effort to solve the problem. Enjoy your answers, but make sure to understand them. At some point your problems will become complicated enough that you won't be able to get trivial help for them. Commented Sep 10, 2021 at 4:06
  • See softwareengineering.meta.stackexchange.com/questions/6166/… Commented Sep 10, 2021 at 4:08

4 Answers 4

3

You can concatenate two parts of the list that both contain the element to duplicate:

def dup_elt(lst, pos=0):
    return lst[:pos+1] + lst[pos:]

If you need to support negative indexes, you can write it like this:

def dup_elt(lst, pos=0):
    return lst[:pos+1 or None] + lst[pos:]
Sign up to request clarification or add additional context in comments.

1 Comment

Ah, this is quite clever.
2

list.insert exists:

def dup_elt(lst, pos=0):
    lst = lst.copy()
    try:
        lst.insert(pos, lst[pos]) 
    except IndexError:
        pass
    return lst

This should correctly support negative indices too.

5 Comments

I have a suspicion this may be the fastest. of course, setting up a meaningful profile would require some work that I'm not feeling like doing right now :)
@juanpa.arrivillaga Slice assignment can be faster than insert, though. Another issue: I think making a copy doesn't overallocate, so that then inserting a value (either way) will reallocate+move and thus cost extra time and space. Maybe it could be more efficient to insert into the original (hoping it's overallocated), then make a copy, then pop from the original, and then return the copy :-)
@don'ttalkjustcode. For a sufficiently small N, I would expect the overhead of the three operations to be more than the copy of N*4 (or *8) bytes.
@MadPhysicist While that question was inserting at the front and the culprit seems to be different ways to shift, I think I also benchmarked inserting at/near the end and slice assignments were also faster there, likely due to not having to load and call a method the way insert does.
@don'ttalkjustcode. I'm terrible at guessing timing results. I still don't understand why np.where is generally faster than np.nonzero. If you post an answer with some timing analysis I'd love to read it.
2

Slice-assignment can handle this easily, actually. And you don't have to check if it is out of bounds because a slice that is out of bounds will return an empty list, and augmented assignment will do nothing!

def dup_elt(lst, pos=0):
    result = lst.copy()
    result[pos:pos + 1] *= 2
    return result

Alternatively, you can just use slicing, taking advantage that a slice out of bounds returns an empty list:

def dup_elt(lst, pos=0):
    return lst[:pos] + lst[pos:pos+1]*2 + lst[pos+1:]

4 Comments

pos in range(len(lst)) is a bit overkill, no? 0 <= pos < len(lst) wouldn't need a range object and seems more legible. Also, value = lst[pos] will check the same thing (except passing through negative indices).
@MadPhysicist value = lst[pos] would check but then might crash, no? Anyway, result[pos : pos+1] *= 2 also works, without checking by us.
@don'ttalkjustcode ah, yeah I would say that's better
@don'ttalkjustcode. I used that crash in my answer. The *= trick is neat
1

Try this with slicing:

def dup_elt(lst, pos=0):
    return lst[:pos] + [lst[pos]] + lst[pos:]

And now:

print(dup_elt([1, 2, 100, 8], 2))

Output:

[1, 2, 100, 100, 8]

2 Comments

Drop the +2, no? And check for out of bounds
@MadPhysicist Oh yes! that's a silly mistake from my end, thanks for catching it

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.