for loop, lst[i] = lst[i - 1] - Python - python

Why doesn't this work?
def func(lst):
for i in range(len(lst)):
lst[i] = lst[i - 1]
return lst
print(func([1, 2, 3, 4]))
Expected output: [4, 1, 2, 3]
Actual output: [4, 4, 4, 4]
why python assign lst[1] = lst[-1] when it should be lst[1] = lst[0]

The following works. lst[i] was reset in the for loop.
def func(lst):
output = []
for i in range(len(lst)):
output.append(lst[i - 1])
return output
print(func([1, 2, 3, 4]))

Swapping has been proposed. Don't do that:
def func(l):
for i in range(len(l) // 2):
l[i], l[-i - 1] = l[-i - 1], l[i]
return l
# func([1, 2, 3, 4]) -> [4, 3, 2, 1]
To move the last element of a given list/array to the first position, as you've described as your desired output, use blhsing's implementation, if your input is a linked list. Python lists are linked lists, and so blhsing's implementation is an efficient one for those. If your input is a contiguous array, like a Numpy array, use this:
def func(l):
l_last = l[len(l) - 1]
for i in range(len(l) - 1, 0, -1):
l[i] = l[i - 1]
l[0] = l_last
return l
Both of our implementations mutate the input list/array.
Why does your function output [4, 4, 4, 4]?
i_max = len(<list>) - 1
<list>[-i] = <list>[len(<list>) - i].
for i in range(len(<list>)) => i_n in {0, 1, ..., i_max}
i_n = 0 => <list>[0] = <list>[i_max - 1].
If <list> = [1, 2, 3, 4], then [1, 2, 3, 4][0] = [1, 2, 3, 4][3] = [4, 2, 3, 4].
In the next iterations, you will repeatedly replace the ith with the i-1th element, so that you get:
[4, 2, 3, 4] => [4, 4, 3, 4] => [4, 4, 4, 4] => [4, 4, 4, 4].

You got a logic error here, at first iteration you doing smth like lst[0] = lst[-1] and then pulling this value to all remaining indeces. If you want to shift array left one pos try something like this:
def shifter(lst):
return lst[-1:] + lst[:-1]

Lists are mutable objects and you are iterating over a single list. On each iteration, the variable lst is pointing to the current state of the list, and inside your loop you are modifying that current state.
Your expected answer would require that Python would copy and remember the initial state of the list at the beginning of the loop, which Python does not do.
def func(lst):
initial = lst[:] # copy lst
for i in range(len(lst)):
lst[i] = initial[i - 1]
return lst
print(func([1, 2, 3, 4]))

def func(lst):
for i in range(len(lst)):
print(i, lst[i-1])
lst[i] = lst[i - 1]
return lst
If you look at how your code executes, the first iteration, i will be 0, and lst[i-1] will be lst[-1] which points to the last element in the array (4). So after first iteration, your array looks likes this:
[4,2,3,4]
In the second, i=1, and lst[i-1] will be lst[0] which has a value a 4 now! So now lst[1] will be 4:
[4,4,3,4]
And so on....
Hope that helps.

You can insert the last item at the first index and delete the last item afterwards:
def func(lst):
lst[:0] = lst[-1:]
del lst[-1:]
return lst
so that func([1, 2, 3, 4]) returns: [4, 1, 2, 3]

Step through your code, one line at a time:
Initially, lst is [1, 2, 3, 4], so len(lst) is 4. range(n) returns values form 0 to n - 1, so your loop will run with the values 0, 1, 2, and 3.
First loop iteration:
i is 0
lst[i] = lst[i - 1] => lst[0] = lst[0 - 1] => lst[0] = lst[-1]
lst is now [4, 2, 3, 4]
Second loop iteration:
i is 1
lst[i] = lst[i - 1] => lst[1] = lst[1 - 1] => lst[1] = lst[0]
lst is now [4, 4, 3, 4]
Third loop iteration:
i is 2
lst[i] = lst[i - 1] => lst[2] = lst[2 - 1] => lst[2] = lst[1]
lst is now [4, 4, 4, 4]
Fourth loop iteration:
i is 3
lst[i] = lst[i - 1] => lst[3] = lst[3 - 1] => lst[3] = lst[2]
lst is now [4, 4, 4, 4]

Related

Need to remove all duplicated values in list

I am trying to solve this question "Good array is the array that does not contain any equal adjacent elements.
Given an integer array A of length N, you are asked to do some operations (possibly zero) to make the
array good. One operation is to remove two equal adjacent elements and concatenate the rest of the array.
A : (1, 2, 2, 3, 4)
An after-one operation : (1, 3, 4)
" With python list, as follow:
L=[]
n=int(input("Enter a num"))
for _ in range(n):
x=int(input())
L.append(x)
print(L)
for z in range(L):
if L[z]==L[z+1]:
L.remove(z)
L.remove(z+1)
print(L)
I keep getting this error: Input In [37]
if L[z]==L[z+1]
^
SyntaxError: invalid syntax
any solutions!!`
Easiest solution is to groupby the array and just keep the groups with only one item:
>>> A = [1, 2, 2, 3, 4]
>>> import itertools
>>> A = [i for i, g in itertools.groupby(A) if len(list(g)) == 1]
>>> A
[1, 3, 4]
Edit
This is NOT correct solution of the above problem. It removes contiguous duplicates from the list. But in question, we need to keep 1 instance of duplicate element.
Please refer to #funnydman solution. Thanks #funnydman for pointing out the mistake :)
You are iterating the list and deleting items from the same :|
Not a good idea!
You can use another list to store the result.
result = []
for z in range(len(L)-1):
if L[z]!=L[z+1]:
result.append(L[z])
result.append(L[-1])
Unfortunately, Nawal's solution does not produce the correct answer, I would suggest this approach:
def get_good_array(alist):
result = []
L = alist + [None]
i = 0
while i < len(L) - 1:
if L[i] != L[i + 1]:
result.append(L[i])
i += 1
else:
i += 2
return result
assert get_good_array([1, 2, 2, 3, 4]) == [1, 3, 4]
assert get_good_array([1, 1, 2, 2, 3, 4]) == [3, 4]
assert get_good_array([0, 1, 1, 2, 2, 3, 4]) == [0, 3, 4]
assert get_good_array([1, 3, 4, 4]) == [1, 3]
assert get_good_array([1, 3, 4, 4, 5]) == [1, 3, 5]
You are missing a : at the end of the if statement, your code should look like the following
L=[]
n=int(input("Enter a num"))
for _ in range(n):
x=int(input())
L.append(x)
print(L)
for z in range(L):
if L[z]==L[z+1]:
L.remove(z)
L.remove(z+1)
print(L)
I guess using <list>.count() is quite intuitive approach. As following,
def deduplicate(l: list):
return [value for value in l if l.count(value) == 1]
assert deduplicate([2]) == [2]
assert deduplicate([2, 2]) == []
assert deduplicate([2, 2, 3]) == [3]
assert deduplicate([2, 2, 2]) == []
assert deduplicate([2, 2, 2, 3]) == [3]

How can I reverse a range of list in python? [duplicate]

This question already has answers here:
How do I reverse a part (slice) of a list in Python?
(8 answers)
Closed 3 years ago.
I have 2 test [0, 2] and [3, 4]
and my list is [1, 2, 3, 4, 5]
how can I reverse only in range from 0-2 and 3-4 to my list
[1, 2, 3, 4, 5] -> [3, 2, 1, 4, 5] -> [3, 2, 1, 5, 4]
this is my code. It only works in first time, and second time it not works!
How can I fix it?
def solution(arr):
test1 = [1, 3]
test2 = [4, 5]
totalTest = [test1, test2]
print(arr)
for x in totalTest:
a = []
for i in x:
a.append(i-1)
lenght = (a[1] - a[0] + 1)/2
index = a[1] - a[0]
# print(lenght)
for i in range(a[0], lenght): # i is the low index pointer
arr[index], arr[i] = arr[i], arr[index]
index -= 1
print(arr)
arr = [1, 2, 3, 4, 5]
solution(arr)
The above code outputs the result:
[3, 2, 1, 4, 5]
[3, 2, 1, 4, 5]
You can use list slicing as follow:
keep in mind that the lower bound is inclusive, but the upper bound is not
so if you want to slice a list from index 0 to index 2 you would do mylist[0:3]
mylist = [1, 2, 3, 4, 5]
mylist = mylist[0:3][::-1] + mylist[3:5][::-1]
# [3, 2, 1, 5, 4]
You can make a more general function to do this:
def reverse_parts(L, ranges):
""" Reverse the parts of list L indicated by pairs of indices in
list ranges
"""
for start, end in ranges:
L = L[:start] + L[start:end+1][::-1] + L[end+1:]
return L
print(reverse_parts([1,2,3,4,5], [(0, 2), (3, 4)])) # [3,2,1,5,4]
Alternatively, to reverse the list in-place:
def reverse_parts(L, ranges):
for start, end in ranges:
L[start:end+1] = reversed(L[start:end+1])
my_list = [1,2,3,4,5]
reverse_parts(my_list, [(0, 2), (3, 4)])
print(my_list)
You should break your list in two and reverse each part separately:
li = [1,2,3,4,5]
print(li[0:3][::-1] + li[3:5][::-1])
cheers!

Indexing with loops in python

The question asks to write a function that takes in some unordered list and from that unordered list pull any sublist that is ordered. Example [5, 2, 1, 3, 4] would become [1,3,4]. My issue is in indexing, I want a way to express that if the current iteration is greater than the one before it, I want to add it. However, the problem that my code runs into is that it compares the first and last of an item.
For my code: [5, 2, 1, 3, 4] => [5,1,3,4]
def numIncreasing(lst):
ans=[]
for index in range(len(lst)):
if lst[index]>=lst[index-1]:
ans.append(lst[index])
elif lst[index]<lst[index-1] and lst[index]<lst[index+1]:
ans.append(lst[index])
else:
continue
return ans
edit: fixed the code not recognizing the start of the pattern
Here is an algorithm that finds the largest ordered sublist:
def increasing2(lst):
length = len(lst)
for size in range(length, 1, -1):
for start in range(0, length - size + 1):
curr = lst[start:start+size]
if all(x <= y for x, y in zip(curr, curr[1:])):
return curr
return None
Which behaves as follows:
>>> increasing2([5, 2, 1, 3, 4])
[1, 3, 4]
Logic of approach:
Loop over all sublists in reversed order, so the largest sublists come before the smaller sublists:
[5, 2, 1, 3, 4]
[5, 2, 1, 3]
[2, 1, 3, 4]
[5, 2, 1]
[2, 1, 3]
[1, 3, 4]
[5, 2]
[2, 1]
[1, 3]
[3, 4]
If the current list is sorted, return it. Otherwise keep going through all the sub lists in order from largest to smallest length. This ensures that you get the largest sublist first. The algorithm also only considers sublists of length 2 or greater.

Alternatives to index() in Python

So for my assignment I must find a way in which I can work around this problem of printing 'YES' if a list contains the elements 1,2,3 in the consecutive order. It does not work if the list contains the elements [3,1,2,3] due to the index method. How can I work around this?
n=int(input("Enter the number of elements: "))
A=[]
for i in range(0,n):
print("Entering element", i)
LstEl=int(input("Please enter the element: "))
A.append(LstEl)
print(A)
for i in range(0,len(A)):
if(1 in A and 2 in A and 3 in A):
post1 = A.index(1)
post2 = A.index(2)
post3 = A.index(3)
if(post1 < post2 and post2 < post3):
print("YES")
break
else:
print('NO')
break
else:
print("NO")
break
Thanks!
one option is just:
# find the indices of all `1`s
one_idxs = (i for (i, v) in enumerate(values) if v == 1)
for idx in one_idxs:
if values[i : i + 3] == [1, 2, 3]:
print('YES')
break
else:
print('NO')
a more concise way is
if any(values[i : i + 3] == [1, 2, 3] for (i, v) in enumerate(values) if v == 1):
print('YES')
else:
print('NO')
Once you find a valid post1 value, you can check for the sequence using
if A[post1:post1+3] == [1, 2, 3]:
print('Yes')
break
Use the other parameters of the index() method to find successive occurrences of the element '1'.
The following code uses a generator function to extract sublists from a larger list. It's probably not appropriate for a homework assignment if you don't understand the mechanics behind generator functions, but it might be something to look into if you're interested.
# A generator function that returns the n-length sublists of list lst
def slider(lst, n):
start = 0
while start + n <= len(lst):
yield lst[start:start+n]
start += 1
# A function that will return True if sequence needle exists in
# haystack, False otherwise
def list_contains(haystack, needle):
for sub in slider(haystack, 3): # Loop through the sublists...
if sub == needle: # ... test for equality ...
return True
return False
# Code
big = [2,4,6,8,0,1,2,3,1,5,7] # Hardcoded here, could be created
# in a loop like you show
seq = [1,2,3] # The sequence you're looking for
print(list_contains(big, seq))
You can see the output of the generator function with something like:
big = [2,4,6,8,0,1,2,3,1,5,7]
for sub in slider(big, 3):
print(sub)
Output:
[2, 4, 6]
[4, 6, 8]
[6, 8, 0]
[8, 0, 1]
[0, 1, 2]
[1, 2, 3]
[2, 3, 1]
[3, 1, 5]
[1, 5, 7]
Or maybe more clearly:
# [2, 4, 6, 8, 0, 1, 2, 3, 1, 5, 7]
[2, 4, 6]
[4, 6, 8]
[6, 8, 0]
[8, 0, 1]
[0, 1, 2]
[1, 2, 3]
[2, 3, 1]
[3, 1, 5]
[1, 5, 7]
I would suggest using enumerate with the for loop.
lst = ['a', 'b', 'c', 'd']
for i, value in enumerate(lst):
print(i, value) # 0,a.....3,d

Python : Generating cyclic permutations code (An unexpected code error to be clarified)

I didn't manage to correct a code I thought it would work for sure. Any advice to make the code functional is accepted.
Expected outputs of the following code is a list containing a cyclic permuation of the list
l = [1,2,3,4] (i.e : [[4, 1, 2, 3],[3, 4, 1, 2],[2, 3, 4, 1],[1, 2, 3, 4]])
Although what I get is : [[2, 3, 4, 1]]
The code :
def cycGen(l):
L=[]
while not(l in L) :
L.append(l)
for i in range(len(l)):
if l[i] == len(l) :
l[i]=1
else :
l[i] = 1 + l[i]
return L
print(cycGen([1,2,3,4]))
Another variation of the solution is to consider the following code wich seems unfortunatly not working either :
def cycGen(l):
L=[]
for k in range(len(l)):
L.append(l)
for i in range(len(l)):
if l[i] == len(l) :
l[i]=1
else :
l[i] = 1 + l[i]
return L
Help me with your generous knowlege sharing please.
You can use collections.deque:
from collections import deque
a = [1, 2, 3, 4]
d = deque(a)
for _ in range(len(a)):
d.rotate()
print(list(d))
Which gives you the output:
[4, 1, 2, 3]
[3, 4, 1, 2]
[2, 3, 4, 1]
[1, 2, 3, 4]
As mentioned in Efficient way to shift a list in python
An easy way is just:
In [12]: x = [1,2,3,4]
In [13]: [x[i:]+x[:i] for i in range(len(x))]
Out[13]: [[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]
In your first code sample, the line L.append(l) appends a "reference" (loosely speaking) to the list l to the end of L, rather than appending a copy as you seem to be expecting. Thus, when l is later modified, the reference to it contained in L is modified as well, and so when l in L is tested, l will equal the reference to itself in L, and so the loop will end. The same basic problem causes your second code sample to return multiples of the same list rather than several different lists.
To store a copy of l at the current point in time in L instead, use L.append(l[:]).
Here is an easy way:
>>> def cycGen(l):
size = len(l)
return [[l[(i+j)%size] for i in range(size)] for j in range(size)]
>>> l = [1,2,3,4]
>>> print cycGen(l)
[[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]
You could do this using a generator too:
a = [1, 2, 3, 4]
def next_pos(max):
i = 0
while True:
for n in xrange(max):
yield n + i
i += 1
pos = next_pos(len(a))
b = []
for i in xrange(len(a)):
n = []
for j in xrange(len(a)):
m = pos.next()
if m >= len(a):
m -= len(a)
n.append(a[m])
b.append(n)
print b
output:
[[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]

Categories

Resources