I am trying to do cyclic rotation of numbers in List in Python.
For example,
An array A consisting of N integers is given. Rotation of the array means that each element is shifted right by one index, and the last element of the array is moved to the first place. For example, the rotation of array A = [3, 8, 9, 7, 6] is [6, 3, 8, 9, 7] (elements are shifted right by one index and 6 is moved to the first place).
The goal is to rotate array A K times; that is, each element of A will be shifted to the right K times.
For example, given
A = [3, 8, 9, 7, 6]
K = 3
the function should return [9, 7, 6, 3, 8]. Three rotations were made:
[3, 8, 9, 7, 6] -> [6, 3, 8, 9, 7]
[6, 3, 8, 9, 7] -> [7, 6, 3, 8, 9]
[7, 6, 3, 8, 9] -> [9, 7, 6, 3, 8]
I have written a function that is supposed to do the above task. Here is my code:
def sol(A, K):
for i in range(len(A)):
if (i+K) < len(A):
A[i+K] = A[i]
else:
A[i+K - len(A)] = A[i]
return A
A = [3, 8, 9, 7, 6]
K = 3
# call the function
sol(A,K)
[9, 3, 8, 3, 8]
I am getting [9, 3, 8, 3, 8] instead of [9, 7, 6, 3, 8].
Can anyone help me with the above code ?
Thanks.
Let's take a look at what happens if K = 1, on just the first iteration:
def sol(A, K):
for i in range(len(A)): # i = 0
if (i+K) < len(A): # i + 1 < 5
A[i+K] = A[i] # A[1] = A[0]
else:
A[i+K - len(A)] = A[i]
# A is now equal to [3, 3, 9, 7, 6] - the element at A[1] got overwritten
return A
The problem is that you don't have anywhere to store the elements you'd be overwriting, and you're overwriting them before rotating them. The ideal solution is to create a new list, populating it with rotated elements from the previous list, and return that. If you need to modify the old list, you can copy elements over from the new list:
def sol(A, K):
ret = []
for i in range(len(A)):
if (i + K) < len(A):
ret.append(A[i + K])
else:
ret.append(A[i + K - len(A)])
return ret
Or, more concisely (and probably how your instructor would prefer you solve it), using the modulo operator:
def sol(A, K):
return [
A[(i + K) % len(A)]
for i in range(len(A))
]
Arguably the most pythonic solution, though, is to concatenate two list slices, moving the part of the list after index K to the front:
def sol(A, K):
return A[K % len(A):] + A[:K % len(A)]
Related
I am working on a Python script which is connected to a server. Every x min, server returns two list but the length of these list is not same. For ex:
a = [8, 10, 1, 34]
b = [4, 6, 8]
As you can see above that a is of length 4 and b is of length 3. Similarly, sometimes it returns
a = [3, 6, 4, 5]
b = [8, 3, 5, 2, 9, 3]
I have to write a logic where I have to check if length of these two list is not same, then add the 0 at the end of the list which is smaller than other list. So for ex, if input is:
a = [3, 6, 4, 5]
b = [8, 3, 5, 2, 9, 3]
then output will be:
a = [3, 6, 4, 5, 0, 0]
b = [8, 3, 5, 2, 9, 3]
What can I try to achieve this?
def pad(list1, list2):
# make copies of the existing lists so that original lists remain intact
list1_copy = list1.copy()
list2_copy = list2.copy()
len_list1 = len(list1_copy)
len_list2 = len(list2_copy)
# find the difference in the element count between the two lists
diff = abs(len_list1 - len_list2)
# add `diff` number of elements to the end of the list
if len_list1 < len_list2:
list1_copy += [0] * diff
elif len_list1 > len_list2:
list2_copy += [0] * diff
return list1_copy, list2_copy
a = [3, 6, 4, 5]
b = [8, 3, 5, 2, 9, 3]
# prints: ([3, 6, 4, 5, 0, 0], [8, 3, 5, 2, 9, 3])
print(pad(a, b))
a = [8, 10, 1, 34]
b = [4, 6, 8]
# prints: ([8, 10, 1, 34], [4, 6, 8, 0])
print(pad(a, b))
For now, I can suggest this solution:
a = [3, 6, 4, 5]
b = [8, 3, 5, 2, 9, 3]
# Gets the size of a and b.
sizeA, sizeB = len(a), len(b)
# Constructs the zeros...
zeros = [0 for _ in range(abs(sizeA-sizeB))]
# Determines whether a or b needs to be appended with 0,0,0,0...
if sizeA < sizeB:
a += zeros
else:
b += zeros
print(a,b)
You should use extend instead of append. This is the way to add a list to another list in Python. The list here is the list of zeros.
a = [3, 6, 4, 5, 9, 3]
b = [8, 3, 5, 2]
lenA, lenB = len(a), len(b)
diff=abs(len(a)-len(b))
if lenA < lenB:
a.extend([0]*diff)
else:
b.extend([0]*diff)
print(a)
print(b)
You could also try to use more_itertools padded() method:
It's prob. more elegant and adaptable for future Use cases.
Notes: just need to do pip install more_itertools first.
# simple example to demo it:
from more_itertools import padded
print(list(padded([1, 2, 3], 0, 5))) # last num: 5 is the numbers of 0 to be padded to make the total length to be 5. (needs 2 zeros)
# [1, 2, 3, 0, 0]
# more examples:
>>> L = [1, 2, 3]
>>> K = [3, 4, 5, 6, 8, 9]
>>> gap = len(K) - len(L)
# 3
# shorter list is L
>>>list(padded(L, 0, len(L) + gap))
[1, 2, 3, 0, 0, 0]
I try to solve this problem:
initial list = [0, 1, 2, 2]
You get this sequence of numbers [0, 1, 2, 2] and you need to add every time the next natural number (so 3, 4, 5, etc.) n times, where n is the element of its index. For example, the next number to add is 3, and list[3] is 2, so you append [3] 2 times. New list will be: [0, 1, 2, 2, 3, 3]. Then the index of 4 is 3, so you have to append 4 three times. The list will be [0, 1, 2, 2, 3, 3, 4, 4, 4] and so on. ([0, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10])
In order to solve this, I tried various approaches. I used recursion, but a recursive approach is very slow in this case. I tried as well the mathematical formula from OEIS (A055086) => a(n) = ceiling(2*sqrt(n+1)) - 2. The problem with the formula is that after 2 ** 20 it is too imprecise.
So, my next idea was to use memoization:
lst = [0, 1, 2, 2]
from itertools import repeat
def find(n):
global lst
print(lst[-1], n, flush = True)
if len(lst) > n:
return lst[n]
for number in range(lst[-1]+1, n+1):
lst += list(repeat(number, lst[number]))
if len(lst) > n:
return lst[n]
Now, this approach works until 2 ** 37, but after this is just timing out. The site where I try to implement my algorithm is (https://www.codewars.com/kata/5f134651bc9687000f8022c4/train/python). I don't ask for a solution, but for any hint on how to optimize my code.
I googled some similar problems and I found that in this case, I could use the total sum of the list, but is not very clear to me yet how could this help me.
Any help is welcomed!
You can answer it iteratively like so:
def find(n):
lst = [0,1,2,2]
if n < 4:
return lst[n]
to_add = 3
while n >= len(lst):
for i in range(lst[to_add]):
lst.append(to_add)
to_add += 1
return lst[n]
You could optimise for large n by breaking early in the for loop, and by keeping track of the list length separately, rather than calls to len
I want to create a new list where each element can be present at max 2 times.
My code:
def valid_element(elements):
removed = 0
new_list = []
for i in elements:
if i not in new_list:
new_list.append(i)
else:
removed += 1
print(new_list)
print('Removed:', removed)
valid_element([1, 2, 3, 3, 3, 3, 4, 5, 8, 8])
The output I want:
Removed: 2
[1, 2, 3, 3, 4, 5, 8, 8]
You need to count unique elements in the list..
def valid_element(elements):
removed = 0
new_list = []
for i in elements:
if i not in new_list:
new_list.append(i)
elif i in new_list:
repeat_count = new_list.count(i)
if repeat_count < 2:
new_list.append(i)
else:
removed = i
print(new_list)
print('Removed:', removed)
valid_element([1, 2, 3, 3, 3, 3, 4, 5, 8, 8])
Output:
[1, 2, 3, 3, 4, 5, 8, 8]
Removed: 3
Your example shows items in sorted order. If duplicates are next to each other then you can do
from itertools import groupby, islice
alist = [1, 2, 3, 3, 3, 3, 4, 5, 8, 8]
result = [i for k, g in groupby(alist) for i in islice(g, 2)]
result contains
[1, 2, 3, 3, 4, 5, 8, 8]
If you need to know how many were removed you can do
num_removed = len(alist) - len(result)
If your original list is not in sorted order, and you don't mind reordering then do
result = [i for k, g in groupby(sorted(alist)) for i in islice(g, 2)]
Finally, here's a version that preserves order
from collections import Counter
c = Counter()
result = [i for i in alist if c.update([i]) or c[i] <= 2]
Hi im trying to solve this question:
Not all of the elements are important. What you need to do here is to remove from the list all of the elements before the given one.
exemple:
remove_all_before([1, 2, 3, 4, 5], 3) == [3, 4, 5]
remove_all_before([1, 1, 2, 2, 3, 3], 2) == [2, 2, 3, 3]
remove_all_before([1, 1, 2, 4, 2, 3, 4], 2) == [2, 4, 2, 3, 4]
remove_all_before([1, 1, 5, 6, 7], 2) == [1, 1, 5, 6, 7]
remove_all_before([], 0) == []
remove_all_before([7, 7, 7, 7, 7, 7, 7, 7, 7], 7) == [7, 7, 7, 7, 7, 7, 7, 7, 7]
For the illustration we have a list [3, 4, 5] and we need to remove all elements that go before 3 - which is 1 and 2.
We have two edge cases here: (1) if a cutting element cannot be found, then the list shoudn't be changed. (2) if the list is empty, then it should remain empty.
def remove_all_before(items: list, border: int) -> Iterable:
limit = border
item_list = items
for i in item_list:
if i < limit:
return items[i+1:]
elif limit not in item_list:
return items
this is my code so far...and im stuck.
thanks for the help
this can be solved by using the index method of list and try and except command. here is the solution-
def remove_all_before(item, border):
try:
#search for the item
index = item.index(border)
print(f'the border is found at index {index}')
return item[index:]
except ValueError:
print('border not present')
return item
def remove_all_before(items: list, border: int) -> Iterable:
# your code here
for i in range(0, len(items)):
if (items[i] == border):
return items[i:]
return items
in my opinion this is the best solution, in this one you have the verification if border is in items
def remove_all_before(items, border):
result1 = []
result2 = []
for i in range(len(items)):
if (items[i] == border):
result1 = items[i:]
return result1
result2.append(items[i])
if (result1 == []):
return result2
else:
return result1
I want to take input of 2 numbers: the number of rows and the number of columns. I then want to use these to output a matrix numbered sequentially. I want to do this using a list comprehension. The following is a possible output.
>>>> my_matrix = matrix_fill(3, 4)
>>>> my_matrix
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
I am using the following code to output a sequentially numbered list:
def matrix_fill(num_rows, num_col):
list=[i for i in range(num_col)]
return (list)
I cannot, however, figure out how to make the sequential list of numbers break into the separate lists as shown in the output based on num_rows.
I don't think you need itertools for that. The range function can take a step as a parameter. Like this:
def matrix_fill(rows,cols):
return [[x for x in range(1,rows*cols+1)][i:i+cols] for i in range(0,rows*cols,cols)]
And then it works as expected.
>>> matrix_fill(3,4)
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
Let's break this down a little bit and understand what's happening.
>>> [x for x in range(1,3*4+1)]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
So what we want to do is to get a new slice every four elements.
>>> [x for x in range(1,3*4+1)][0:4]
[1, 2, 3, 4]
>>> [x for x in range(1,3*4+1)][4:8]
[5, 6, 7, 8]
>>> [x for x in range(1,3*4+1)][8:12]
[9, 10, 11, 12]
So we want to iterate over the elements of the list[x for x in range(1,3*4+1)] of length "rows*cols" ( 3 * 4 ), create a new slice every "cols" number of elements, and group these slices under a single list. Therefore, [[x for x in range(1,rows*cols+1)][i:i+cols] for i in range(0,rows*cols,cols)] is a suitable expression.
Nest a list comprehension inside another one, use itertools.count() to generate the sequence:
import itertools
rows = 3
cols = 4
count_gen = itertools.count() # pass start=1 if you need the sequence to start at 1
my_matrix = [[next(count_gen) for c in range(cols)] for r in range(rows)]
print(my_matrix)
# prints: [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]
# As a function
def matrix_fill(rows, cols):
count_gen = itertools.count()
return [[next(count_gen) for c in range(cols)] for r in range(rows)]
If you used the numpy module, the method is extremely simple, with no list comprehension needed.
my_matrix = np.arange(1, 13).reshape(3,4)
Printing the variable my_matrix shows
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]