Accessing a variable value from a python function inside another function - python

I have one function that calls for the function rlEncode which is supposed to take the data list and compress it so it counts how many values in a row there are and would output for example [1, 5, 3, 2, 5, 6] and so on. But when I run it just out puts the [1,5] again and again and not moving the n value over however so many spaces in the list. How would I get the n value from the function rlEncode to be used in the other function?
def rlEncode(n, z, data_list):
while data_list[n] == data_list[n+1]:
z = z + 1
n = n + 1
while data_list[n] != data_list[n+1]:
return n
return z
def unitTest( ):
c = 0
n = 0
z = 1
data_list = [1,1,1,1,1,3,3,5,5,5,5,5,5,6,8,8,1,1,1,5,5,5,5,13,14, 14]
compress_list = [ ]
while c < (len(data_list)):
n = rlEncode(n, 1, data_list)
z = rlEncode(0, z, data_list)
rlEncode(0, 1, data_list)
compress = [data_list[n], z]
c = c + 1
compress_list = compress_list + compress
print(compress_list)
n = n+1

Python passes immutable objects by value. See this previous answer: How do I pass a variable by reference?
The simplest solution in your case is to have the inner function return the value of n to the outer function, which assigns it to its local n.
compress is a list, which is mutable, so you can use += to mutate the list in place rather than creating a new local variable.
I also added a check against the list length, otherwise the references to n+1 will cause IndexError.
I also don't think you need the second while loop in rlEncode but I'll leave that up to you to sort out... :)
def rlEncode(n, z, data_list, compress):
while (n < len(data_list)-1) and (data_list[n] == data_list[n+1]):
z = z + 1
n = n + 1
while (n < len(data_list)-1) and (data_list[n] != data_list[n+1]):
compress += [data_list[n], z]
n = n + 1
return n
def unitTest(data_list):
c = 0
n = 0
compress = []
while c < (len(data_list)):
n = rlEncode(n, 1, data_list, compress)
c = c + 1
return ('list: ', data_list, "compressed list: ", compress)
sample_data = [1,1,1,1,1,3,3,5,5,5,5,5,5,6,8,8,1,1,1,5,5,5,5,13, 14, 14]
unitTest(sample_data)

I like doing these things recursively. Python isn't great with recursion but I wanted to see how it's done so I guess I'll share:
def compress(lst):
if not lst:
return []
current = lst[0]
result = compress(lst[1:])
if not result:
# item is last
return [(1, current)]
nxt = result[0][1]
if current == nxt:
# items is same as next
return [(result[0][0] + 1, current)] + result[1:]
# different items
return [(1, current)] + result
To use it:
print [x[0] for x in compress(lst)]
The obvious and efficient way would be a generator:
def group_gen(lst):
buff = []
for item in lst:
if buff and item == buff[0]:
buff.append(item)
else:
if buff:
yield buff
buff = [item]
if buff:
yield buff
print list(map(len, group_gen(lst)))
Check it using:
print list(map(len, group_gen(lst)))

Related

Given an array of N integers, and an integer K, find the number of pairs of elements in the array whose sum is equal to K

Problem Statement:- Given an array of N integers, and an integer K, find the number of pairs of elements in the array whose sum is equal to K.
**def countpairs(x,length,sum):
count = 0
for i in range(0,length):
for j in range(i+1,length):
print(x[i],x[j])
if(x[i]+x[j]==sum):
count+=1
print(count)
x = [1, 1, 1, 1]
sum = 2
length=len(x)
countpairs(x,length,sum)
Output:= 6**
This is My solution used in VS code.
My Question:- whenever I am running the same code in gfg it is not accepting the code giving me this error. I even have tried the same code in the online compiler there also it is running correctly.
This Is the gfg code which i have written
class Solution:
def getPairsCount(self, arr, K, N):
count = 0
for i in range(0,N):
for j in range(i+1,N):
if(arr[i]+arr[j]==K):
count+=1
return count
#Initial Template for Python 3
if __name__ == '__main__':
tc = int(input())
while tc > 0:
n, k = list(map(int, input().strip().split()))
arr = list(map(int, input().strip().split()))
ob = Solution()
ans = ob.getPairsCount(arr, n, k)
print(ans)
tc -= 1
Error
if(arr[i]+arr[j]==K):
IndexError: list index out of range
There's no added value in using a class for this. You just need:-
def getPairsCount(arr, K):
count = 0
for i in range(len(arr)-1):
if arr[i] + arr[i+1] == K:
count += 1
return count
EDIT:
Previous answer assumed that only adjacent elements were to be considered. If that's not the case then try this:-
import itertools
def getPairsCount(arr, K):
count = 0
for c in itertools.combinations(sorted(arr), 2):
if c[0] + c[1] == K:
count += 1
return count
data = [1, 2, 1, 4, -1]
print(getPairsCount(data, 3))
We do not need two loops for this question. Here is something that runs in O(n):
def countpairs(list_,K):
count = 0
set_ = set(list_)
pairs_ = []
for val in list_:
if K - val in set_:
# we ensure that pairs are unordered by using min and max
pairs_.append ( (min(val, K-val), max(val, K-val)) )
count+=1
set_pairs = set(pairs_)
print ("Pairs which sum up to ",K," are: ", set_pairs)
return len(set_pairs)
x = [1,4,5,8,2,0,24,7,6]
sum_ = 13
print ("Total count of pairs summming up to ", sum_, " = ", countpairs(x, sum_))
Output:
Pairs which sum up to 13 are: {(6, 7), (5, 8)}
Total count of pairs summming up to 13 = 2
The idea is that if two values should sum to a value K, we can iterate through the array and check if there is another element in the array which when paired with the current element, sums up to K. The inner loop in your solution can be replaced with a search using the in. Now, we need this search to be fast (O(1) per element), so we create a set out of our input array (set_ in my example).
def solve(a,K):
freq = {}
for v in a:
if v in freq:
freq[v] += 1
else:
freq[v] = 1
for i in range(len(set(a))):
res += freq[a[i]] * freq[K - a[i]]
return res
a = [int(v) for v in input().split()]
K = int(input())
print(solve(a,K))
# Time Complexity : O(N)
# Space Complexity : O(1)
def solve(a,K):
freq = {}
for v in a:
if v in freq:
freq[v] += 1
else:
freq[v] = 1
for i in range(len(set(a))):
res += freq[a[i]] * freq[K - a[i]]
return res
a = [int(v) for v in input().split()]
K = int(input())
print(solve(a,K))

Recursion gives me completely wrong answers

I want to find the number of ways, a given integer X can be decomposed into sums of numbers which are N-th powers and every summand must be unique. For example if X = 10 and N=3, I can decompose this number like that:
10 = 2^3+1^3+1^3 ,but this is not a valid decomposition, because the number 1 appears twice. A valid decomposition for X = 10 and N = 2 would be 10 = 3^2+1^2, since no summand is repeating here.
Now I tried it to use recursion and created the following Python Code
st = set(range(1,int(pow(X,1/float(N))))) # generate set of unique numbers
print(str(ps(X, N, st)))
def ps(x, n, s):
res = 0
for c in s:
chk = x-pow(c,n) # test validity
if chk > 0:
ns = s-set([c])
res += ps(chk,n,ns)
elif chk == 0:
res += 1 # one result is found
else:
res += 0 # no valid result
return res
I used a set called st and then I recursively called the function ps that includes the base case "decomposition found" and "decomposition not found". Moreover it reduces a larger number to a smaller one by considering only the ways how to decompose a given number into only two summands.
Unfortunately, I get completely wrong results, e.g.
X = 100, N = 3: Outputs 0, Expected 1
X = 100, N = 2: Outputs 122, Expected 3
X = 10, N = 2: Outputs 0, Expected 1
My thoughts are correct, but I think the Problem is anywhere in the recursion. Does anybody see what I make wrong? Any help would be greatly appreciated.
Hint:
>>> X = 100
>>> N = 3
>>> int(pow(X, 1/float(N)))
4
>>> list(range(1, 4))
[1, 2, 3]
The output is indeed correct for the input you are feeding it.
The problem is line res += 1 # one result is found in conjuction with res += ps(chk,n,ns) will make the algorithm add twice.
E.g X = 10, N = 2: Outputs 0, Expected 1 because:
c=1:
10 - 1^2 > 0 -> res += ps(chk,n,ns)
c=3:
9 - 3^2 == 0 -> res += 1 # one result is found ... return res
So, in c=3 res=1 is returned to the c=1 call, which will
res += ps(chk,n,ns), and ps(chk,n,ns) = 1, making res = 2 and doubling the result expected.
E.g. X = 29, N = 2.
29 = 2^2 + 3^2 + 4^2
Solving from bottom to top (the algorithm flow):
c=4 -> res += 1... return res
c=3 -> res += ps() -> res += 1 -> res = 2 ... return res
c=2 -> res += ps() -> res += 2 -> res = 4 ... return res
But res is supposed to be 1.
Solution: You cannot add res to res. And you must remove the previous iterated objects to avoid path repetition. Check the solution below (with prints for better understanding):
def ps(x, n, s):
print(s)
print("")
return ps_aux(x, n, s, 0) # level
def ps_aux(x, n, s, level):
sum = 0
for idx, c in enumerate(s):
print("----> " * level + "C = {}".format(c))
chk = x - pow(c,n) # test validity
if chk > 0:
ns = s[idx + 1:]
sum += ps_aux(chk,n,ns, level + 1)
elif chk == 0:
print("OK!")
sum += 1 # one result is found
else:
sum += 0 # no valid result
return sum
Try with:
X=10 # 1 solution
N=2
st = list(range(1,int(pow(X,1/float(N))) + 1 )) # generate set of unique numbers
print(str(ps(X, N, st)))
X=25 # 2 solutions [3,4], [5]
N=2
st = list(range(1,int(pow(X,1/float(N))) + 1 )) # generate set of unique numbers
print(str(ps(X, N, st)))

How to delete specific elements from an array while not deleting its later occurences

Take integer input from a user and then delete the elements from an array having those many consecutive ocurences from the array.
Eg the input array is "aabcca" and the input from the user is 2.
Then the answer should be "ba".
I tried it when the elements are not repeated. My code works perfectly for examples like "aaabbccc".
for j in range(t, (n+1)):
if (t == n):
if (count == k):
array = [x for x in array if x != temp]
print array
exit()
if (t == n and count == k):
array = [x for x in array if x != temp]
print array
exit()
if temp == data[j]:
count += 1
t += 1
if temp != data[j]:
if count == k:
array = [x for x in array if x != temp]
temp = data[t]
count = 1
t += 1
you can use sliding window or two pointers to solve it.
the key point is use [start, end] range to record a consecutive seq, and only add the seq whose length less than n:
def delete_consecutive(s, n):
start, end, count = 0, 0, 0
res, cur = '', ''
for end, c in enumerate(s):
if c == cur:
count += 1
else:
# only add consecutive seq less than n
if count < n:
res += s[start:end]
count = 1
start = end
cur = c
# deal with tail part
if count < n:
res += s[start:end+1]
return res
test and output:
print(delete_consecutive('aabcca', 2)) # output: ba
print(delete_consecutive('aaabbccc', 3)) # output: bb
Hope that helps you, and comment if you have further questions. : )
Here is one way to do that:
def remove_consecutive(s, n):
# Number of repeated consecutive characters
count = 0
# Previous character
prev = None
# Pieces of string of result
out = []
for i, c in enumerate(s):
# If new character
if c != prev:
# Add piece of string without repetition blocks
out.append(s[i - (count % n):i])
# Reset count
count = 0
# Increase count
count += 1
prev = c
# Add last piece
out.append(s[len(s) - (count % n):])
return ''.join(out)
print(remove_consecutive('aabcca', 2))
# ba
print(remove_consecutive('aaabbccc', 2))
# ac
print(remove_consecutive('aaabbccc', 3))
# bb

How do I get smallest postitive integer not present in the array

I am trying to find out smallest positive number not present in the list a
def smallitem(a):
a = sorted(set(a))
lst = []
for item in a:
item + = 1
if item not in a:
lst.append(item)
continue
mst = []
for item in lst:
if item < 1:
item += 1
if item not in a:
mst.append(item)
continue
n = 0
if mst:
n = min(mst)
return n or min(lst)
I think I have got the solution but it doesnt look correct to me the way I have done it.
for example:
smallitem([-1, -3]) # 1
smallitem([1,3,6,4,1,2, 87]) # 5
You can convert the list to a set and then keep incrementing a positive integer from 1 until it is not found in the set:
def smallitem(a):
set_a = set(a)
i = 1
while i in set_a:
i += 1
return i
Perhaps there's a lighter way do this.
The time complexity is always O(n).
def small_item(a):
s = set(a)
for i in range(1, max(s)):
if i not in s:
return i
return max(max(s) + 1, 1)
print small_item([1,3,6,4,1,2, 87])
print small_item([-1, -3])
Here's anther way to do this:
def smallitem(l):
l = list(set(sorted(l)))
x = l[0]
for i in l:
if i != x and x >= 1:return x
x += 1
return 1
Testing:
>>> smallitem([-3, -1])
1
>>> smallitem([1, 3, 6, 4, 1, 2, 87])
5
>>>

Get the absolute difference between elements of a circular array

Let's say I have a array like l = [1, 3, 4, 5, 6, 8]
where the nth element represents the distance between the nth and n+1th object.
I want to find the distance between any two objects, and I used this code for this:
def dis(l_list, index1, index2, mylist):
m = mylist.index(index1)
n = mylist.index(index2)
i=0
j=0
if n > m:
while n >= m:
i = i + mylist[m]
m = m + 1
elif n < m:
while n <= m:
i = i + mylist[n]
n = n + 1
else:
return(0)
j = mylist[n] % l_mylist
print(abs(i - j))
l_mylist = input()
l_mylist = int(l_mylist)
mylist = []
mylist = list(map(int, input().split()))
i,j = input().split()
i, j=int(i), int(j)
dis(l_mylist, i, j, mylist)
but I am still getting the wrong output. Can anyone please point out where I am wrong?
If you want to sum around a potentially circular list. You can use a collections.deque() to rotate the list, e.g.:
from collections import deque
def dist(l, i1, i2):
d = deque(l)
d.rotate(-i1)
return sum(list(d)[:i2-i1]))
In []:
l = [1,2,3,4,5,6,7,8]
dist(l, 3-1, 6-1) # 3, 4, 5
Out[]:
12
In []:
dist(l, 6-1, 3-1) # 6, 7, 8, 1, 2
Out[]:
24
def distance(first_index, second_index, my_list):
temp_list = my_list + my_list
if (first_index > second_index):
first_index += len(my_list)
requested_sum = sum(my_list[second_index-1:first_index-1])
else:
requested_sum = sum(my_list[first_index-1:second_index-1])
return requested_sum
If I understood you correctly, then this should do the trick.
There are much more compact and efficient ways to do this, but this is the simplest and easiest to understand in my opinion.

Categories

Resources