The following code iterates through the whole matrix filled in with increasing numbers and checks the difference between every element in one row and elements in the same location of the previous row. For every iteration, if this difference of two elements is less than 3, the counter increases and then the loop breaks and continues to the next row. What I would like to do is trying to increase this loop every time there is a counter increase.
In other words, if for instance the loop runs into this condition after checking the first two rows and each row is length 3, the following iterations should be done considering row length = 6, and if this condition is met again later, then the considered row length should be 9 and so on.
To be clear, this code returns 3 but according to what I am trying to do, it should return 1.
I am not sure if this would be possible in python, but I will gladly consider suggestions.
I am sorry for not being clear but this is a bit hard to explain correctly, I will still try my best and feel free to ask me any specific questions that you may have, I'll be happy to answer. In this example, the loop subtracts the second row [4,6,6] from the first one [1,2,4] and since 4-1=3, 6-2=4 and 6-4=2, only the latter is less than 3 therefore k increases by 1. Then in the third with the second row, 7-6=1 which is < 3 therefore 8-6 does not need to be checked, and here too, k increases by 1, so now we have k=2, and in the last row, [9,9,10]-[7,7,8] gives us elements less than 3 therefore our k=3.
Now, what I am trying to do is the following:
once [4,6,6]-[1,2,4] increases k by 1, I would like the 1st and 2nd row to be treated as one sublist [1,2,4,4,6,6], therefore even the 3rd and 4th row will be one sublist [7,7,8,9,9,10] to subtract [1,2,4,4,6,6] from, which would not increase k as there are no elements whose difference is less than 3. If let's say this example had additional rows, then for each k increase, the matrix should be 'reshaped' every time by enlarging the sublist length of 3 additional elements.
I hope I am explaining this clearly enough. If not, feel free to ask.
matrix=[[1,2,4],
[4,6,6],
[7,7,8],
[9,9,10]]
cell_list=[]
for row in matrix:
for cell in row:
cell_list.append(cell)
len_cell_list=(len(cell_list))
len_matrix_row=len(matrix[0])
k=0
k_list=[]
for i in range(1,len(matrix)):
for j in range(len_matrix_row):
if abs(matrix[i][j]-matrix[i-1][j])<3:
k+=1
k_list.append(k)
break
continue
print(k_list[-1])
I think this is what you want.
import numpy
matrix=[[1,2,4],
[4,6,6],
[7,7,8],
[9,9,10]]
k = 0
end_of_matrix = False
changing_matrix = matrix[:]
while not end_of_matrix:
end_current_loop = False
for i in range(1, len(changing_matrix)):
for j in range(len(changing_matrix[i])):
if abs(changing_matrix[i][j] - changing_matrix[i-1][j]) < 3:
k += 1
end_current_loop = True
break
if end_current_loop:
break
if not end_current_loop:
end_of_matrix = True
else:
changing_matrix = []
for i in range(0, len(matrix), k+1):
changing_matrix.append(list(numpy.concatenate(matrix[i:i+k+1])))
print(changing_matrix)
print(k)
Output:
[[1, 2, 4, 4, 6, 6], [7, 7, 8, 9, 9, 10]]
1
Related
With reference to Kelly's Short O(n) solution at
Python sum of number in array, ignoring sections of specific numbers
Can someone explain to me why the numbers between 6 and 9 are not included in the sum? I have tried deriving the answer myself using:
def summer_70(lst):
it = iter(lst)
return sum(x for x in it
if x != 4 not in it)
print(summer_70([4, 5, 6, 7, 8, 9])) #Output 5 not 35 ??
But I still do not understand how the code executes.
Thanks in advance :D
I'll take the code from Kelly's answer as your's lacks the or operator.
Generate iterator from the given list
it = iter(lst)
For each entity in the given iterator, start summing it.
return sum(x for x in it
if x != 6 or 9 not in it)
If the current value we are iterating not equals 6, the or condition already return True and it adds it to the sum.
Once we find x == 6, we go into the other condition
9 not in it
Currently, the iterator contains only the remaining values we didn't sum.
This condition will iterate the rest of the values until it finds a 9.
If it didn't found a 9, then we summed only the values until the first 6.
If it finds a 9, the iterator will point on the next value after the 9 (this way we skipped the values between 6 to 9), and we'll do the same if condition again (sum if it's not 6, or check again until we find a 9)
Given
lst = [1,2,6,7,8,9,10]
When we reach the 6, we already summed 1, 2.
Then, the or condition will search for 9 in the remaining list:
[7,8,9,10]
Found 9, and the remaining list:
[10]
Sum 10 and we'll get
1+2+10 = 13
Link to the accepted answer - https://stackoverflow.com/a/68975493/3125312
The code in question
def summer_69(lst):
it = iter(lst)
return sum(x for x in it
if x != 6 or 9 not in it)
Lets work through this with an example.
Say we have a list of numbers
[1,2,6,7,9,5]
and we need calculate the sum skipping any region starting with a 6 and ending with a 9. The sum would be 8.
We can start by trying to solve it using a simpler but longer code
set a counter total to 0 - this will be the default sum
set a flag should_skip to let us know if we need to skip a number or not
iterate through the list and add all numbers but only if should_skip is False
Now the most important question arises - how do we know if we should skip a number? Checking whether a number is a 6 or 9 is not enough as we need a skip a whole section which may include other numbers as well. This is where we make use of the should_skip flag. And we need to check only 2 conditions.
If we hit a 6 in our iteration we know this is the start of the section to skip. so we set should_skip to True
If we hit a 9 in out iteration then this is the end of the section to skip. we can set should_skip to False.
We can add to the total if should_skip is False
Converting this into code looks like
input = [1, 2, 6, 7, 9, 5]
total = 0 # The default sum
should_skip = False
for number in input:
if number == 6:
# start of the section to skip, keep skipping till we reach a 9
should_skip = True
if not should_skip:
# add it to the total!
total += number
if number == 9:
# End of section to skip, we can start adding numbers to the total
should_skip = False
print(total) # 8
If you can understand the above logic then it will be extremely easy to understand the shorter implementation. Lets get back to it and start analyzing.
There are 2 necessary things that both codes are doing. "iterating" through the code and "summming" the numbers that are not in a section to skip.
We wrote the code for it ourselves but Python has inbuilt function for it as well called iter and sum
iter is a function that returns an iterator object. whats special about iterators is that they are memory efficient and that they remove an element when proceeding to the next one.
e.g
if our iterator contains iter(3,6,4)
after one iteration the contents look like iter(6,4)
and after the second iteration there is only one element remaining i.e. iter(4)
sum as the name suggests returns the sum. the default is 0
def summer_69(lst):
it = iter(lst) # turn our input into an iterator object
return sum(x for x in it # add it to the total!
# but wait we need to check if we are in a section to skip first
if x != 6 # number is not a 6,
or 9 not in it # there are no 9s remaining in the iterator so its safe to add
)
Step by Step breakdown:
1st iteration -> x is 1 and `it` is `[1,2,6,7,9,5]`
2nd iteration -> x is 2 and `it` is `[2,6,7,9,5]`
3rd iteration -> x is 6 and `it` is `[6,7,9,5]`
4th iteration -> x is 7 and `it` is `[7,9,5]`
5th iteration -> x is 9 and `it` is `[9,5]`
6th iteration -> x is 5 and `it` is `[5]`
At each iteration the condition being checked is x != 6 or 9 not in it? this is how we know that we are in a section to skip or not.
number = [1,2,3,4,63,2]
max = number[0]
for large in number:
if large > max:
max = large
print(max)
This Python code prints the largest number in a list and it works, but I am not sure how it works. On the 5th line when max = large I am not quite sure that this if statement is true in the first place because the first item in the list is not bigger than max but it is equal to it.
number = [1,2,3,4,63,2]
max = number[0]
for large in number:
if large > max:
max = large
print(max)
Explanation:
First iteration: max=1 and large=1 so if 1>1 then max=large else the max will the previous number as we assigned 1 initially.
2nd iteration: max will have 2.
.
.
.
4nd iteration: max will have 4.
5nd iteration: max will have 63.
6th iteration: max will have still 63 since 2 is not > 63.
I think I understood your confusion. The statement for large in number: assigns each element of number to large successively no matter what happens in the loop. Python for loops do not have a condition, unlike C-like for loops.
The statement if large > max: is not the condition for the loop to continue. It is totally independent of the loop statement. As you observed correctly, it is False for the first iteration, but that has no effect on what the for loop is doing. Only the value of max is not updated.
It's conventional not to use names like max that shadow built-in names. Something like max_ or max_value is better.
I am not quite sure that this if statement is true in the first place because the first item in the list is not bigger than max but it is equal to it.
Your current loop works perfectly fine and in fact omits useless reassignment of the max variable.
number = [1,2,3,4,63,2]
max = number[0]
for large in number: # For every item in the list of numbers
if large > max: # if a currently selected item is larger than the current maximum
max = large # assign that value of that item to be the new maximum
print(max)
For the first iteration you will get a False. For the given list all other iterations will yield a True. However if you add items that are equal like
[ 1, 1, 2, 3, 4, 4, 4, 4, 5 ]
you will soon discover that the current check you have is quite efficient. Why? Because if you add equality to the check (in which case your IF condition will return more times True including the first iteration)
if large >= max:
max = large
you will end up with pointless reassignment of max every time you get to a value that is equal to the current maximum. So for the list I've given above as an example you will go through 4 reassignments that are completely useless - one for the second 1 and three for the three 4 after the first 4 (marked with * below):
[ 1, 1, 2, 3, 4, 4, 4, 4, 5 ]
| | | |
* * * *
There is one thing I would add to solution and that is omitting the first item:
for large in number[1:]:
...
For your comparison of numbers you will not see much of a difference but if you compare larger objects it will.
Brushing up on dynamic programming (DP) when I came across this problem. I managed to use DP to determine how many solutions there are in the subset sum problem.
def SetSum(num_set, num_sum):
#Initialize DP matrix with base cases set to 1
matrix = [[0 for i in range(0, num_sum+1)] for j in range(0, len(num_set)+1)]
for i in range(len(num_set)+1): matrix[i][0] = 1
for i in range(1, len(num_set)+1): #Iterate through set elements
for j in range(1, num_sum+1): #Iterate through sum
if num_set[i-1] > j: #When current element is greater than sum take the previous solution
matrix[i][j] = matrix[i-1][j]
else:
matrix[i][j] = matrix[i-1][j] + matrix[i-1][j-num_set[i-1]]
#Retrieve elements of subsets
subsets = SubSets(matrix, num_set, num_sum)
return matrix[len(num_set)][num_sum]
Based on Subset sum - Recover Solution, I used the following method to retrieve the subsets since the set will always be sorted:
def SubSets(matrix, num_set, num):
#Initialize variables
height = len(matrix)
width = num
subset_list = []
s = matrix[0][num-1] #Keeps track of number until a change occurs
for i in range(1, height):
current = matrix[i][width]
if current > s:
s = current #keeps track of changing value
cnt = i -1 #backwards counter, -1 to exclude current value already appended to list
templist = [] #to store current subset
templist.append(num_set[i-1]) #Adds current element to subset
total = num - num_set[i-1] #Initial total will be sum - max element
while cnt > 0: #Loop backwards to find remaining elements
if total >= num_set[cnt-1]: #Takes current element if it is less than total
templist.append(num_set[cnt-1])
total = total - num_set[cnt-1]
cnt = cnt - 1
templist.sort()
subset_list.append(templist) #Add subset to solution set
return subset_list
However, since it is a greedy approach it only works when the max element of each subset is distinct. If two subsets have the same max element then it only returns the one with the larger values. So for elements [1, 2, 3, 4, 5] with sum of 10 it only returns
[1, 2, 3, 4] , [1, 4, 5]
When it should return
[1, 2, 3, 4] , [2, 3, 5] , [1, 4, 5]
I could add another loop inside the while loop to leave out each element but that would increase the complexity to O(rows^3) which can potentially be more than the actual DP, O(rows*columns). Is there another way to retrieve the subsets without increasing the complexity? Or to keep track of the subsets while the DP approach is taking place? I created another method that can retrieve all of the unique elements in the solution subsets in O(rows):
def RecoverSet(matrix, num_set):
height = len(matrix) - 1
width = len(matrix[0]) - 1
subsets = []
while height > 0:
current = matrix[height][width]
top = matrix[height-1][width]
if current > top:
subsets.append(num_set[height-1])
if top == 0:
width = width - num_set[height-1]
height -= 1
return subsets
Which would output [1, 2, 3, 4, 5]. However, getting the actual subsets from it seems like solving the subset problem all over again. Any ideas/suggestions on how to store all of the solution subsets (not print them)?
That's actually a very good question, but it seems mostly you got the right intuition.
The DP approach allows you to build a 2D table and essentially encode how many subsets sum up to the desired target sum, which takes time O(target_sum*len(num_set)).
Now if you want to actually recover all solutions, this is another story in the sense that the number of solution subsets might be very large, in fact much larger than the table you built while running the DP algorithm. If you want to find all solutions, you can use the table as a guide but it might take a long time to find all subsets. In fact, you can find them by going backwards through the recursion that defined your table (the if-else in your code when filling up the table). What do I mean by that?
Well let's say you try to find the solutions, having only the filled table at your disposal. The first thing to do to tell whether there is a solution is to check that the element at row len(num_set) and column num has value > 0, indicating that at least one subset sums up to num. Now there are two possibilities, either the last number in num_set is used in a solution in which case we must then check whether there is a subset using all numbers except that last one, which sums up to num-num_set[-1]. This is one possible branch in the recursion. The other one is when the last number in num_set is not used in a solution, in which case we must then check whether we can still find a solution to sum up to num, but having all numbers except that last one.
If you keep going you will see that the recovering can be done by doing the recursion backwards. By keeping track of the numbers along the way (so the different paths in the table that lead to the desired sum) you can retrieve all solutions, but again bear in mind that the running time might be extremely long because we want to actually find all solutions, not just know their existence.
This code should be what you are looking for recovering solutions given the filled matrix:
def recover_sol(matrix, set_numbers, target_sum):
up_to_num = len(set_numbers)
### BASE CASES (BOTTOM OF RECURSION) ###
# If the target_sum becomes negative or there is no solution in the matrix, then
# return an empty list and inform that this solution is not a successful one
if target_sum < 0 or matrix[up_to_num][target_sum] == 0:
return [], False
# If bottom of recursion is reached, that is, target_sum is 0, just return an empty list
# and inform that this is a successful solution
if target_sum == 0:
return [], True
### IF NOT BASE CASE, NEED TO RECURSE ###
# Case 1: last number in set_numbers is not used in solution --> same target but one item less
s1_sols, success1 = recover_sol(matrix, set_numbers[:-1], target_sum)
# Case 2: last number in set_numbers is used in solution --> target is lowered by item up_to_num
s2_sols, success2 = recover_sol(matrix, set_numbers[:-1], target_sum - set_numbers[up_to_num-1])
# If Case 2 is a success but bottom of recursion was reached
# so that it returned an empty list, just set current sol as the current item
if s2_sols == [] and success2:
# The set of solutions is just the list containing one item (so this explains the list in list)
s2_sols = [[set_numbers[up_to_num-1]]]
# Else there are already solutions and it is a success, go through the multiple solutions
# of Case 2 and add the current number to them
else:
s2_sols = [[set_numbers[up_to_num-1]] + s2_subsol for s2_subsol in s2_sols]
# Join lists of solutions for both Cases, and set success value to True
# if either case returns a successful solution
return s1_sols + s2_sols, success1 or success2
For the full solution with matrix filling AND recovering of solutions you can then do
def subset_sum(set_numbers, target_sum):
n_numbers = len(set_numbers)
#Initialize DP matrix with base cases set to 1
matrix = [[0 for i in range(0, target_sum+1)] for j in range(0, n_numbers+1)]
for i in range(n_numbers+1):
matrix[i][0] = 1
for i in range(1, n_numbers+1): #Iterate through set elements
for j in range(1, target_sum+1): #Iterate through sum
if set_numbers[i-1] > j: #When current element is greater than sum take the previous solution
matrix[i][j] = matrix[i-1][j]
else:
matrix[i][j] = matrix[i-1][j] + matrix[i-1][j-set_numbers[i-1]]
return recover_sol(matrix, set_numbers, target_sum)[0]
Cheers!
lst = [3, 4, 1, 2, 9]
givenSum = 12
table = {}
x = 0
y = 0
for i in range(0, len(lst)):
table[givenSum - lst[i]] = 1
i += 1
for x in table:
for y in table:
if (x + y) == givenSum:
print(x, "and", y, "is equal to", givenSum)
break
This is the output
9 and 3 is equal to 12
3 and 9 is equal to 12
I don't know why it's being shown up twice. I need to find a pair of values that add up to the given sum and this is the only way I could think of. I only want it to show up once though any ideas on how I can do that?
There are better solutions, but to fix your issue making minimal changes to your code:
lst = [3, 4, 1, 2, 9]
givenSum = 12
for x in range(0, len(lst) - 1):
for y in range(x + 1, len(lst)):
if lst[x] + lst[y] == givenSum:
print(lst[x], "and", lst[y], "is equal to", givenSum)
break
This will print
3 and 9 is equal to 12
Note that the redundant table is completely removed from the code.
If you run it for a better test case:
lst = [3, 4, 5, 6, 7, 1, 2, 9]
it will print
3 and 9 is equal to 12
5 and 7 is equal to 12
First, to address why the looping continues and gives a second output, break can only break out of its immediate loop. Since you have a nested loop, the break only stops the for y in table: inner loop, but allows for x in table outer loop to move onto it's next iteration. So eventually, x is able to take the value of 3 later on, thus giving you the two outputs you see.
So, if you need a way to stop the iteration entirely when a solution is found, you need to either chain the break statements using a for else syntax (which arguably might be tough to read) as follows,
for x in table:
for y in table:
if (x + y) == givenSum:
print(x, "and", y, "is equal to", givenSum)
break #breaks from inner loop
else: #for else syntax: this block runs if and only if there was no break encountered during looping.
continue #jumps the outer loop to next iteration
break #this break is set at outer loop's level. Essentially, we can only reach this portion if there is a break in the inner loop.
For else says: run through the whole iteration, and if no break is found, executes the code in the else block. Essentially, the "else" of a "for else" is like a "for - no break".
However, one easier alternative is to use a function with a return (which also makes it easier to read the code).
def find_given_sum(lst, givenSum):
table = {}
x = 0
y = 0
for i in range(0, len(lst)):
table[givenSum - lst[i]] = 1
i += 1
for x in table:
for y in table:
if (x + y) == givenSum:
print(x, "and", y, "is equal to", givenSum)
return #this returns immediately out of the function, thus stopping the iteration.
Also, you could just repeat the break condition, but repeating code is generally not a good practice.
Hope this helps address why the two outputs are being printed. Now, as for the solution itself, there's actually a much better way to solve this. It builds upon the idea of compliments, which you seem to have a sense of in your table. But it doesn't require iteration over the table itself. As a hint: the ideal solution runs in O(n) time. I will not discuss the ideal solution, but hope this prompts you to find the best approach.
Looping twice for n elements costs you O(N^2) time, which is inefficient for large lists. Modified and tested the code to use hash map/dictionary to store the list elements and now it will take only O(N) time.
Map = dict()
lst = [3, 4, 1, 2, 9]
givenSum = 12
for i in range(0, len(lst)):
rem=givenSum-lst[i]
if rem in Map:
print lst[i],lst[Map[rem]]
else:
Map[lst[i]]=i
Store the value of each list element into the map whenever it does not exist in the map.
At each iteration, take the difference between givenSum and current element at that iteration and then search for that difference in the Map.
If it exists it means the pair exists or else not.
In this approach you are running the loop only once, which takes O(N) time because accessing elements in hash map is O(1)/constant time.
Use itertools to get the result
import itertools
sum = 10
lst = [3, 4, 1, 2, 9]
ans = list(filter(lambda x : x[0]+x[1] == sum,itertools.combinations(lst, 2)))
when I have this array
A = [1,2,3]
i did this basic for-loop to iterate over the entire array except the last position
index = 0
for i in range(1,len(A)-1):
print(i)
if A[i] > A[index]:
index = i
it is suposed to do 2 iterations but when I print "i", this is the output
1
PS. I tried with this array and it worked absolutely fine
B= [7,5,14,2,8,8,10,1,2,3]
any hint about what is happening? thanks for your time
edit = I already put the index declaration
edit 2 = Problem solved
I'm assuming you want to create a list of items bigger than a certain value if so this is how:
a = 5
b = [1, 5, 6, 2, 10, 69, 42, 7]
c = []
for I in b:
if I > a:
c.append(I)
print(*c)
Your question is very unclear, what exactly is your objective?
The range() function returns a sequence of numbers, starting from 0 by default, and increments by 1 (by default), and ends at a specified number.
Syntax:
range(start, stop, step)
Here, one important thing to note is that the stop is exclusive. So, if you run a loop from 1 to len(A)-1, then actually it will run from 1 to len(A)-2, which is only one iteration in your code.
So, in order to do two iterations replace range(1,len(A)-1) with range(0,len(A)-1) or range(len(A)-1) if you want to start from index 0, or range(1,len(A)) if you want to start from 1 and do two iterations.