How to Reverse an array in groups in python? - python

I am trying to reverse the array in groups but I am getting this error:
:---- for i in arr: TypeError: 'NoneType' object is not iterable.
What's wrong with my code?
def reverseSubarray(arr,n,k):
if k == 1:
return
i = 0
while i < n:
l = i
r = min(i+k-1, n-1)
while l < r:
temp = arr[l]
arr[l] = arr[r]
arr[r] = temp
l += 1
r -= 1
i += k
return arr
def main():
n = int(input().strip())
string = input().strip().split()
arr=[]
for j in string:
arr.append(int(j.strip()))
k=int(input().strip())
arr = reverseSubarray(arr,n,k)
for i in arr:
print(i,end=' ')
if __name__ == "__main__":
main()

So the problem is that you're actually returning None. This happens because most likely you're giving k=1 so it will go to that line where you return nothing, which will return this error when trying to iterate.
You can treat the problem with a try-catch block on arr=reverseSubarray(arr,n,k) that will return a message like k cannot be 1

You can reverse an array in groups in python as given below,
def reverseSubarray(arr, N, K):
for i in range(0, len(arr),K):
l=arr[i:i+K]
l.reverse()
arr[i:i+K] =l
return arr

While your error was indeed coming from the fact that your function is returning None as other answers have pointed out, you have also written the function in a very non-pythonic style. Here is an example of how you could rewrite it more succintly:
def reverseInGroups(self, arr, N, K):
for i in range(0, N, K):
arr[i:i+K] = reversed(arr[i:i+K])
return arr
range(0, N, K) will return an iterator that goes from 0 to N-1 in steps of K. In other word, i will successively have value: 0, K, 2K, 3K, 4K, etc. until the last multiple of K that is less than N. Here is the documentation for more details.
arr[i:i+K] will refer to the slice of arr between indices i and i+K-1 or, put another way, [arr[i], arr[i+1], arr[i+2], ..., arr[i+K-1]]. It stops at i+K-1 so that you can naturally use arr[i:i+K] and arr[i+K:] without counting arr[i+K] twice.
reversed... reverses an iterator. Here's the doc.

Related

(python) Can you please tell me what is the problem in the code below

I just start to learn python and i have a problem:
arr = [1,3,3,3,0,1,1]
def solution(arr):
a=[]
for r in range(len(arr)-1):
if arr[r] == arr[r+1]:
a.append(r+1)
print(a)
for i in range(len(a)):
k = int(a[i])
arr[k] = -1
arr.remove(-1)
return arr
There's a message
IndexError: list index out of range for ''arr[k] = -1''
Can you please tell me the reason for the Error and correct it?
Of course, it results in a Runtime exception. The list a stores indices. For each element v in a, you are trying to remove the value arr[v]. Doing this will reduce the size of arr by one every time. So, in the next iteration, v can be greater than the size of arr. Hence, it results in List index out of bound exception.
Your code, corrected:
arr = [1,3,3,3,0,1,1]
def solution(arr):
a=[]
for r in range(len(arr)-1):
if arr[r] == arr[r+1]:
a.append(r+1)
print(a)
c = 0
for i in range(len(a)):
k = int(a[i])
arr[k - c] = -1
arr.remove(-1)
c += 1
return arr
print(solution(arr))
It looks like you are trying to remove consecutive duplicates from the list. This can be easily solved using the following code.
def remove_duplicates(arr):
stack = [arr[0]]
for i in range(1, len(arr)):
if stack[-1] != arr[i]:
stack.append(arr[i])
return stack
print(remove_duplicates([1,3,3,3,0,1,1]))
In short, you cannot modify the array shape when you have determined the indices based on the unmodified array to index into it.
Here is something that you might be looking for:
def solution(arr):
a = []
for r in range(len(arr) - 1):
if arr[r] == arr[r + 1]:
a.append(r + 1)
print(a)
for i in range(len(a)):
k = int(a[i])
arr[k] = -1
# In the following line, you cannot modify the array length
# when you have already computed the indices based on the unmodified array
# arr.remove(-1)
arr = [x for x in arr if x != -1] # This is a better way to deal with it
return arr
print(solution(arr=[1, 3, 3, 3, 0, 1, 1]))
You don’t want to mess with the original list. Otherwise you’ll run into index errors. Index errors mean the item you were looking for in the list no longer exists. Most likely this line was the culprit arr.remove(-1).
arr = [1,3,3,3,0,1,1]
solution = []
for i, v in enumerate(arr):
if i == 0 or v != arr[i -1]:
solution.append(v)
print(solution)
This should get you what you are after. enumerate tells you want index you are at when looping through the list. More information can be found here: https://realpython.com/python-enumerate/
Well, you've probably already know what wrong happened here, removing the element inside the loop:
for i in range(len(a)):
k = int(a[i])
arr[k] = -1
arr.remove(-1)
You can fix the whole thing just changing the line to this list filter+lambda implementation, well, not inside the loop, but after the completion of loop iterations, just like follows:
for i in range(len(a)):
k = int(a[i])
arr[k] = -1
arr = list(filter(lambda x: x != -1, arr))
And you'll get what you want just from your solution!

Permutations without itertools for two values (using recursion!)

Stackoverflow, I am once again asking for your help.
I'm aware there are other threads about this but I'll explain what makes my assignment different.
Basically my function would get a list of 0s and 1s, and return all the possible orders for the string. For example for "0111" we will get "0111", "1011", "1101", "1110".
Here's my code:
def permutations(string):
if len(string) == 1:
return [string]
lst = []
for j in range(len(string)):
remaining_elements = ''.join([string[i] for i in range(len(string)) if i != j])
mini_perm = permutations(remaining_elements)
for perm in mini_perm:
new_str = string[j] + perm
if new_str not in lst:
lst.append(new_str)
return lst
The problem is when I run a string like "000000000011" it takes a very long time to process. There is supposed to be a more efficient way to do it because it's just two numbers. So I shouldn't be using the indexes?
Please help me if you can figure out a more efficient say to do this.
(I am allowed to use loops just have to use recursion as well!)
Here is an example for creating permutations with recursion that is more efficient:
def permute(string):
string = list(string)
n = len(string)
# Base conditions
# If length is 0 or 1, there is only 1 permutation
if n in [0, 1]:
return [string]
# If length is 2, then there are only two permutations
# Example: [1,2] and [2,1]
if n == 2:
return [string, string[::-1]]
res = []
# For every number in array, choose 1 number and permute the remaining
# by calling permute recursively
for i in range(n):
permutations = permute(string[:i] + string[i+1:])
for p in permutations:
res.append([''.join(str(n) for n in [string[i]] + p)])
return res
This should also work for permute('000000000011') - hope it helps!
You can also use collections.Counter with a recursive generator function:
from collections import Counter
def permute(d):
counts = Counter(d)
def get_permuations(c, s = []):
if len(s) == sum(counts.values()):
yield ''.join(s)
else:
for a, b in c.items():
for i in range(1, b+1):
yield from get_permuations({**c, a:b - i}, s+([a]*i))
return list(set(get_permuations(counts)))
print(permute("0111"))
print(permute("000000000011"))
Output:
['0111', '1110', '1101', '1011']
['010000100000', '100000000001', '010000001000', '000000100001', '011000000000', '100000000010', '001001000000', '000000011000', '100000001000', '100000100000', '100001000000', '001000100000', '100010000000', '000000001100', '000100000100', '010010000000', '000000000011', '000000100010', '101000000000', '110000000000', '100000010000', '000100001000', '000001001000', '000000000101', '000000100100', '010000000001', '001000000100', '001000000010', '000110000000', '000011000000', '000001100000', '000000110000', '001000000001', '000010001000', '000100100000', '000001000001', '000010000001', '001100000000', '000100000001', '001000001000', '010000000100', '010000010000', '000000010001', '001000010000', '010001000000', '100000000100', '100100000000', '000000001001', '010100000000', '000010100000', '010000000010', '000000001010', '000010000100', '001010000000', '000000010010', '000001000010', '000100000010', '000101000000', '000000010100', '000100010000', '000000000110', '000001000100', '000010010000', '000000101000', '000001010000', '000010000010']
posting an answer someone gave me. Thanks for your responses!:
def permutations(zeroes, ones, lst, perm):
if zeroes == 0 and ones == 0:
lst.append(perm)
return
elif zeroes < 0 or ones < 0:
return
permutations(zeroes - 1, ones, lst, perm + '0')
permutations(zeroes, ones - 1, lst, perm + '1')

Unravel recursion inside double for loop to avoid stack overflow

I have the following code. It's about as simple as I can make it. Does anyone know of a slick way to turn this recursion into a loop?
The problem is that I can run into a recusion limit. I've thought of some ways to rewrite it, but they're not pretty at all.
My nicest thought at this point is that I could get it into some tail recursion form, but I'm not sure how to do that.
def blackbox(c, i): #This is a different function in production
if i > 5:
return range(0,1)
else:
return range(0,c+i)
def recurse(c, length):
if length == 0:
return [[]]
return [l + [j] for j in blackbox(c, length) for l in recurse(c - j, length - 1)]
Example: recurse(6, 1000) throws an error is way over the recursion limit.
Cool, mostly useless fact: Using range(i, c + 1) for the black box returns all the lists with length length with sum at most c.
EDIT: I'm aware I can memoize the code, but that doesn't fix recursion limit. In this example, memoizing helps the speed a lot, but in my situation it doesn't, so I'm not concerned with it.
EDIT 2: Updated blackbox so the value of recurse(6,1000) is reasonable.
One way can be to use your own stack of generator functions instead:
def blackbox(c, i):
return range(0, c + i) #This code is actually quite different, treat it as a black box
# For testing at the end
def recurse(c, length):
if length == 0:
return [[]]
return [l + [j] for j in blackbox(c, length) for l in recurse(c - j, length - 1)]
# Non-recursive variant following:
gen_stack = []
def gen_driver():
prevResult = None
while gen_stack:
try:
if prevResult is not None:
gen_stack[-1].send(prevResult)
prevResult = None
else:
next(gen_stack[-1])
except StopIteration as si:
prevResult = si.value
del gen_stack[-1]
return prevResult
def nonrecurse(c, length):
if length == 0:
return [[]]
# Unfortunately the concise list comprehension doesn't work
result = []
for j in blackbox(c, length):
gen_stack.append(nonrecurse(c - j, length - 1))
for l in (yield):
result.append(l + [j])
return result
gen_stack.append(nonrecurse(6, 10))
# Testing equality of both variants
print(gen_driver() == recurse(6,10))
# No crash but I didn't wait until it was ready
gen_stack.append(nonrecurse(6, 1000))
Slightly shorter variant but needs more care:
gen_stack = []
def gen_driver():
prevResult = None
while gen_stack:
try:
if prevResult is not None:
gen_stack.append(gen_stack[-1].send(prevResult))
prevResult = None
else:
gen_stack.append(next(gen_stack[-1]))
except StopIteration as si:
prevResult = si.value
del gen_stack[-1]
return prevResult
def single_generator(value):
return value
yield # Mark it as generator function
def nonrecurse(c, length):
if length == 0:
return single_generator([[]])
return [l + [j] for j in blackbox(c, length) for l in (yield nonrecurse(c - j, length - 1))]
gen_stack.append(nonrecurse(6, 10))
# Testing equality of both variants
print(gen_driver() == recurse(6,10))
While in the first variant nonrecurse was a generator function, it is now a usual function returning generators where the list comprehension is a generator on its own.

Largest even number in a list using fold

I want to accomplish this:
Construct a function that takes in a list as a parameter and returns the biggest even number in that list.
Do this by using the "fold" function in Python
I thought it might be something along the lines of:
def fold(f, v, l):
for x in l:
v = f(v, x)
return v
def biggest_even_number(xs):
l = [i for i in xs if i % 2 == 0]
return fold(l)
I know this is wrong but I just don't know how to set this up. How would I accomplish the above task using the "fold" function?
fold function looks good. You just need to call it with correct arguments:
def biggest_even_number(xs):
l = [i for i in xs if i % 2 == 0]
return fold(max, float("-inf"), l)
If it is not a homework, you can use builtin reduce() which basically does the same thing:
def biggest_even_number(xs):
l = [i for i in xs if i % 2 == 0]
return reduce(max, l, float("-inf"))
Thanks to #Steven Rumbalski, for anyone trying to find the maximum value of a sequence, you don't even need reduce:
def biggest_even_number(xs):
return max(i for i in xs if i % 2 == 0)
Do something like the following:
def fold(l):
biggest = float("-inf")
for i in l:
biggest = max(i, biggest)
return biggest
def biggest_even_number(xs):
l = [i for i in xs if i % 2 == 0]
return fold(l)

looping through loops in python?

I'm trying to solve this problem on the easy section of coderbyte and the prompt is:
Have the function ArrayAdditionI(arr) take the array of numbers stored in arr and return the string true if any combination of numbers in the array can be added up to equal the largest number in the array, otherwise return the string false. For example: if arr contains [4, 6, 23, 10, 1, 3] the output should return true because 4 + 6 + 10 + 3 = 23. The array will not be empty, will not contain all the same elements, and may contain negative numbers.
Here's my solution.
def ArrayAddition(arr):
arr = sorted(arr, reverse=True)
large = arr.pop(0)
storage = 0
placeholder = 0
for r in range(len(arr)):
for n in arr:
if n + storage == large: return True
elif n + storage < large: storage += n
else: continue
storage = 0
if placeholder == 0: placeholder = arr.pop(0)
else: arr.append(placeholder); placeholder = arr.pop(0)
return False
print ArrayAddition([2,95,96,97,98,99,100])
I'm not even sure if this is correct, but it seems to cover all the numbers I plug in. I'm wondering if there is a better way to solve this through algorithm which I know nothing of. I'm thinking a for within a for within a for, etc loop would do the trick, but I don't know how to do that.
What I have in mind is accomplishing this with A+B, A+C, A+D ... A+B+C ... A+B+C+D+E
e.g)
for i in range(len(arr):
print "III: III{}III".format(i)
storage = []
for j in range(len(arr):
print "JJ: II({}),JJ({})".format(i,j)
for k in range(len(arr):
print "K: I{}, J{}, K{}".format(i,j,k)
I've searched all over and found the suggestion of itertool, but I'm wondering if there is a way to write this code up more raw.
Thanks.
A recursive solution:
def GetSum(n, arr):
if len(arr) == 0 and n != 0:
return False
return (n == 0 or
GetSum(n, arr[1:]) or
GetSum(n-arr[0], arr[1:]))
def ArrayAddition(arr):
arrs = sorted(arr)
return GetSum(arrs[-1], arrs[:-1])
print ArrayAddition([2,95,96,97,98,99,100])
The GetSum function returns False when the required sum is non-zero and there are no items in the array. Then it checks for 3 cases:
If the required sum, n, is zero then the goal is achieved.
If we can get the sum with the remaining items after the first item is removed, then the goal is achieved.
If we can get the required sum minus the first element of the list on the rest of the list the goal is achieved.
Your solution doesn't work.
>>> ArrayAddition([10, 11, 20, 21, 30, 31, 60])
False
The simple solution is to use itertools to iterate over all subsets of the input (that don't contain the largest number):
def subsetsum(l):
l = list(l)
target = max(l)
l.remove(l)
for subset_size in xrange(1+len(l)):
for subset in itertools.combinations(l, subset_size):
if sum(subset) == target:
return True
return False
If you want to avoid itertools, you'll need to generate subsets directly. That can be accomplished by counting in binary and using the set bits to determine which elements to pick:
def subsetsum(l):
l = list(l)
target = max(l)
l.remove(l)
for subset_index in xrange(2**len(l)):
subtotal = 0
for i, num in enumerate(l):
# If bit i is set in subset_index
if subset_index & (1 << i):
subtotal += num
if subtotal == target:
return True
return False
Update: I forgot that you want to check all possible combinations. Use this instead:
def ArrayAddition(l):
for length in range(2, len(l)):
for lst in itertools.combinations(l, length):
if sum(lst) in l:
print(lst, sum(lst))
return True
return False
One-liner solution:
>>> any(any(sum(lst) in l for lst in itertools.combinations(l, length)) for length in range(2, len(l)))
Hope this helps!
Generate all the sums of the powerset and test them against the max
def ArrayAddition(L):
return any(sum(k for j,k in enumerate(L) if 1<<j&i)==max(L) for i in range(1<<len(L)))
You could improve this by doing some preprocessing - find the max first and remove it from L
One more way to do it...
Code:
import itertools
def func(l):
m = max(l)
rem = [itertools.combinations([x for x in l if not x == m],i) for i in range(2,len(l)-1)]
print [item for i in rem for item in i if sum(item)==m ]
if __name__=='__main__':
func([1,2,3,4,5])
Output:
[(1, 4), (2, 3)]
Hope this helps.. :)
If I understood the question correctly, simply this should return what you want:
2*max(a)<=sum(a)

Categories

Resources