def my_len(lst):
mylen = 0
for i in lst:
mylen = 1
return mylen
def insrt(lst, what, where):
length = my_len(lst)
tmp = [0] * (length 1)
for i in range(0, where):
tmp[i] = lst[i]
tmp[where] = what
for i in range(where, length 1):
tmp[i] = lst[i - 1]
return tmp
def move(lst, from_index, to_index):
a = lst[from_index]
del lst[from_index]
insrt(lst, a, to_index)
return lst
my intention was if the original list input is [1, 2, 3, 4, 5, 6], then print(move(lst, 3, 1) will give [1, 4, 2, 3, 5, 6], but my code gives [1, 2, 3, 5, 6]. Please explain how to fix it.
CodePudding user response:
NB. See the end of the answer for an alternative interpretation of the move
If you want the item to end up in the defined to_index
, you can simply use list.insert
and list.pop
:
def move(lst, from_index, to_index):
lst.insert(to_index, lst.pop(from_index))
examples:
l = [1, 2, 3, 4, 5, 6]
move(l, 1, 3)
print(l)
[1, 3, 4, 2, 5, 6]
l = [1, 2, 3, 4, 5, 6]
move(l, 3, 1)
print(l)
[1, 4, 2, 3, 5, 6]
l = [1, 2, 3, 4, 5, 6]
move(l, 3, 3)
print(l)
[1, 2, 3, 4, 5, 6]
NB. your function should probably either return a copy, or modify the list in place, not both. (here I chose to modify in place, see below for a variant).
copy variant:
def move(lst, from_index, to_index):
lst = lst.copy()
lst.insert(to_index, lst.pop(from_index))
return lst
l = [1, 2, 3, 4, 5, 6]
l2 = move(l, 1, 3)
print(l)
[1, 2, 3, 4, 5, 6]
print(l2)
[1, 3, 4, 2, 5, 6]
alternative interpretation: move to the position as defined before the move
In this different interpretation, the item moves to the position as defined if the insertion occured before the deletion.
In this case we need to correct the insertion position if it is greater than the initial position.
We can take advantage of the boolean/integer equivalence by subtracting to_index>from_index
(1 if True
, 0 otherwise)
def move(lst, from_index, to_index):
lst.insert(to_index-(to_index>from_index), lst.pop(from_index))
l = [1, 2, 3, 4, 5, 6]
move(l, 1, 3)
print(l)
# [1, 3, 2, 4, 5, 6]
CodePudding user response:
This would work,
def move(lst, from_index, to_index):
new_lst = lst[:to_index] [lst[from_index]] [item for item in lst[to_index:]]
new_lst.pop(from_index 1)
return new_lst
lst = [1, 2, 3, 4, 5, 6]
move(lst, 3, 1)
Output -
[1, 4, 2, 3, 5, 6]
CodePudding user response:
The main problem you're seeing right now relates to how your insrt
function works, as compared to how you're calling it.
The way you've written it, insert
returns a new list containing the values from the old list plus one new value at a particular index. But when you call it in move
, you seem to be expecting it to modify the given list in place. It doesn't do that. You need to change at least one of the two functions so that they match up. Either make insrt
work in-place, or make move
save the value returned by it rather than throwing it away.
Anyway, here's a very simple tweak to your move
function that makes it work properly with the insrt
function as you've shown it:
def move(lst, from_index, to_index):
a = lst[from_index]
del lst[from_index]
new_lst = insrt(lst, a, to_index) # save the new list after the insert
return new_lst # and then return it
I'd note that using del
on the earlier line already modifies the lst
passed in, so this design may not make a whole lot of sense. You might want to modify insrt
to work in place instead, to be consistent. That would look something like this (which would work with your original move
):
def insrt(lst, what, where):
length = my_len(lst)
lst.append(None) # add a dummy value at the end of the list
for i in range(length-1, where, -1): # iterate backwards from the end
lst[i] = lst[i - 1] # shift each value back
lst[where] = what # plug in the new value
# no return any more, this version works in place