AN implementation of Crohn(Крона) algorithm used in Scheduling theory, is it possible to change the data of the current index in a for loop in python?
I have a code like so;
link to the full code
#list1 is a 2d array
list1 = [[12, 3, 17], [14], [10, 12, 15]]
cond = 1
while cond:
d = delta(sum_calc(list1))
#delta() finds the difference between the list with the highest sum
#and the list with the minimum sum, then returns the
#difference(d[0]), index_of_list_with_max_sum(d[1]), #index_of_list_with_min_sum(d[2])
#d = [23, 2, 1]
if cond == 0:
break
else:
for i in list1[d[1]]:
if d[0] > i:
move(list1[d[1]], list1[d[2]])
#move() moves the min element from list1, to list2
else:
cond = 0
what I am trying to do is, given an index, loop through the elements of that list, then check if num is greater than i (element), after that we do some operations, like moving the smallest element from the current list we are looping from, to another list. then we have some operations, after that I want to change the value of i, to something like
#the index might change
i = l[index]
the problem I am facing is that when I do that, it continues looping from the first index.
Is there a way I can reset it, so that it starts looping from other elements?
I HAVE USED A WHILE LOOP, because I want the procedure to repeat itself and until d[0] !> i:
#since the list with the highest sum is list1[2], we got 2 from d,
#next step is to loop through the elements in that list and check if
#there's an element which is less than d[0](the difference between max and min sum)
#expected results
#after first iteration
list1 = [[12, 3, 17], [14, 10], [12, 15]]
d = [8, 0, 1]
#after second iteration
list1 = [[12, 17], [14, 10, 3], [12, 15]]
d = [2, 0, 1]
#the problem is it stops here, I want it to calculate delta again then #repeat the process, but after debugging, i found that in the second #iteration i = 15, which the second element of the list, but it should #be like that.
Try to combine while loop with index ?
example:
lst = [1,2,3]
idx = 0
while idx < len(lst):
print(lst[idx])
idx += 1
if idx == len(lst):
# Reset index
idx = 0
EDIT
After debugging I found your errors - You havent been assigning the new delta result to d where you have been referencing from your code thus you never got the new indexes
cond = True
idx = 0
while cond and idx < len(l[d[1]]):
if d[0] > l[d[1]][idx]:
move(l[d[1]], l[d[2]])
s = sum_calc(l)
d = delta(s)
print("l =", l)
print("s =", s)
print("d =", d)
print("")
idx = 0
else:
cond = False
idx += 1
Output:
l = [[12, 3, 17], [14, 10], [12, 15]]
s = [32, 24, 27]
d = [8, 0, 1]
l = [[12, 17], [14, 10, 3], [12, 15]]
s = [29, 27, 27]
d = [2, 0, 1]
Related
Let's say I have two lists:
List1
[26, 45, 15]
List2
[13, 15, 20]
Assuming there is always exactly one element that is the same between the two lists, how would I reorder list2 into:
[20, 13, 15]
Where 15 becomes the third element of list2 because 15 is the third element of list1 (While the order of 13, 15, and then 20 is kept)? I have tried something like this:
# Reorder list2 to correspond with list1
key = 0
newOrder = []
for i in range(3):
for j in range(3):
if list2[i] == list1[j]: # if elements
key = i - j
for k in range(3):
index = k + key
if index == 3:
index = 0
if index == -1:
index = 2
newOrder.append(list2[index])
but it doesn't have a 100% success rate.
Assuming you want to rotate list2 so that the "shared" element is in the same position as in list1.
First, to get the matching indices you do not have to compare all elements. Instead, you can use a dict to store which element is at which position, and then get the matching position in a single pass over list2 (if the lists always have just 3 elements this does not matter, but for longer lists it reduces the complexity from O(n²) to O(n))
list1 = [26, 45, 15]
list2 = [13, 15, 20]
pos2 = {x: i for i, x in enumerate(list2)}
p1, p2 = next((i, pos2[x]) for i, x in enumerate(list1) if x in pos2)
Then, you can use a list comprehension to get the "rotated" elements from list2 using modulo % to "wrap around" when the index is larger than the length of the list.
n = len(list2)
res = [list2[(i+p2-p1) % n] for i in range(n)]
print(res) # [20, 13, 15]
This code gets the value and the index of the number in list1 that also exists in list2.
list1 = [26, 45, 15]
list2 = [13, 15, 20]
index, number = next((idx,number) for idx, number in enumerate(list1) if number in list2)
Then it removes the number from list2 and inserts it again at the wanted index:
list2.remove(number)
list2.insert(index,number)
print(list2)
Output will be
[13, 20, 15]
def row_sums(square):
"""takes such a (possibly magic) square as a parameter and returns a list of the row sums"""
total_each_row = 0
combine_each_total = []
for row in square: #row is an entire row
for cell in row: #cell is an element of row
total_each_row += cell #possible error
combine_each_total.append(total_each_row) #possible error
return combine_each_total
magic_square = [
[2, 7, 6],
[9, 5, 1],
[4, 3, 8]
]
print(row_sums(magic_square))
This program running out as [15, 30, 45] but what I want to get is [15, 15, 15] as the sum of each row and allocate the sums in the same list.
After the first row finished its sum calculation, how to make a new total for the second and the following rows for each one and append each sum into the same list?
The square would be containing all the integers from 1 up to n**2 inclusive.
In the end, returns a list of the row sums
Are there any other ways to achieve the result without using the built-in sum function in this case?
(Sorry I should emphasize this point)
Just use pythons sum function for each row.
Arr=[]
for row in square:
Arr.append(sum(row))
return Arr
If you want to use your code the problem with it is that you dont make sure that your sum row var equals to 0 so its keeping the count from last row.
magic_square = [
[2, 7, 6],
[9, 5, 1],
[4, 3, 8]
]
# functional/pythonic way
sums = [sum(row) for row in magic_square] # [15, 15, 15]
# if you want to make it longer
def row_sums(square):
return [sum(row) for row in square]
row_sums(magic_square) # [15, 15, 15]
#if you want to make it even longer
def row_sums(square):
sums = []
for row in square:
row_total = 0
for number in row:
row_total += number
sums.append(row_total)
return sums
row_sums(magic_square) # [15, 15, 15]
You need to reinitialize combine_each_total to 0 before summing again for new row.
def row_sums(square):
"""takes such a (possibly magic) square as a parameter and returns a list of the row sums"""
combine_each_total = []
for row in square: #row is an entire row
total_each_row = 0
for cell in row: #cell is an element of row
total_each_row += cell #possible error
combine_each_total.append(total_each_row) #possible error
return combine_each_total
magic_square = [
[2, 7, 6],
[9, 5, 1],
[4, 3, 8]
]
print(row_sums(magic_square))
output:
[15,15,15]
I would like to return the duplicates in two different 2d lists. But I'm having trouble figuring out what code to write. For example I would like variable "a" to compare to variable "b" and return the duplicates. Here are my two 2d list below.
a = [[2,3,6,8],[4,5,7,8,10],[15,17,21,22],[12,13,14,23,25]]
b = [[4,5,6],[15,17,21,22],[2,3,4],[2,3,6,8],[5,7,8,12,15],[7,12,14,17,32],[5,6,7,12,14]]
I would like my results to be:
c = [[2,3,6,8],[15,17,21,22]]
You just need to check if a list in a is also in b or not.
a = [[2,3,6,8],[4,5,7,8,10],[15,17,21,22],[12,13,14,23,25]]
b = [[4,5,6],[15,17,21,22],[2,3,4],[2,3,6,8],[5,7,8,12,15],[7,12,14,17,32],[5,6,7,12,14]]
c=[]
for i in a:
if i in b:
c.append(i)
print(c)
Output:
[[2, 3, 6, 8], [15, 17, 21, 22]]
This should work, it should get you started -
import itertools
#Input lists
a = [[2,3,6,8],[4,5,7,8,10],[15,17,21,22],[12,13,14,23,25]]
b = [[4,5,6],[15,17,21,22],[2,3,4],[2,3,6,8],[5,7,8,12,15],[7,12,14,17,32],[5,6,7,12,14]]
#Take a product of both the lists ( a X b )
z = itertools.product(a,b)
#Uncomment the following to see what itertools.product does
#[i for i in z]
#Return only the elements which the pair of the same element repeats (using string match)
[i[0] for i in z if str(i[0])==str(i[1])]
[[2, 3, 6, 8], [15, 17, 21, 22]]
one liner list comprehension approach:
dups = [i for i in a if i in b]
output:
[[2, 3, 6, 8], [15, 17, 21, 22]]
Try this:
a = [[2,3,6,8],[4,5,7,8,10],[15,17,21,22],[12,13,14,23,25]]
b = [[4,5,6],[15,17,21,22],[2,3,4],[2,3,6,8],[5,7,8,12,15],[7,12,14,17,32],[5,6,7,12,14]]
c = []
for i in a + b:
if (a + b).count(i) > 1 and i not in c:
c.append(i)
#mulaixi's answer is OK but in output list you may see duplicates.
I'm a super n00b in python.
I have been struggling with finding proper solution.
Here is the list, L = [0, 0, 0, 3, 4, 5, 6, 0, 0, 0, 0, 11, 12, 13, 14, 0, 0, 0, 18, 19, 20], and each of the items refers to location in the list.
I wanted to make list from the upper list, showing smaller lists inside the list, and each of the elements represents starting location of the series, end of the series and number of elements. This should be [[3, 6, 4], [11, 14, 4], [18, 20, 3]]. How could I write code for this? Following is what I have done so far.
target = []
target.append([])
target.append([])
target.append([])
L = [0,0,0,0,4,5,6,7,8,9,0,0,0,13,14,15,0,0,0,19,20,21]
for i in L :
if i == 0 :
L.remove(i)
continue
elif i != 0 :
startpoint = i
i = i * i
while i != 0 :
i += 1
continue
else :
j = i
endpoint = i - 1
break
target[0].append(startpoint)
target[1].append(endpoint)
target[2].append(j)
About your code one mistake is that in following while :
while i != 0 :
i += 1
You must not increase i you need to increase the index of elements not itself!then continue to appending when you find a none zero element!
But as a more pythonic way You can use itertools.groupby with a list comprehension :
>>> from itertools import groupby
>>> [[i[0],i[-1],len(i)] for i in [list(g) for _,g in groupby(L,key=lambda x:x!=0)]if i[0]!=0]
[[3, 6, 4], [11, 14, 4], [18, 20, 3]]
Note that groupby returns the grouped elements as a generator (g) and when you want to loop over it you dont need to convert it to list but in this case as we need the length we must convert to list till we can use len function.
Here's a version based on your attempt:
L=[0,0,0,3,4,5,6,0,0,0,0,11,12,13,14,0,0,0,18,19,20]
target = []
i = 0
while i < len(L):
if L[i] == 0 :
i += 1
continue
start = i
while i < len(L) and L[i] != 0:
i += 1
target.append((L[start],L[i-1],i-start))
A = [a1, a2, a3...] #a1<a2<a3...
B = [b1, b2...] #b1<b2<b3...
A and B are disjoint. are I do not know the number of elements and the value of them in A/B in advance. I want to compare the value of the elements in both list and delete elements iff:
delete a[i+1] if there is no b[j] such that a[i]<b[j]<a[i+1]
delete b[i+1] if there is no a[j] such that b[i]<a[j]<b[i+1]
At the end, I want to separate list, not a combination of A and B.
For example, If A[0] < B[0], A = [1, 10, 40], B = [15, 30]. Compare A[1] and B[0] first. Delete 10 because no element in B are in between 1 and 15.
Then delete 15 since no element exist anymore btw 15 and 30. The output should be: if you try to order the elements of the new 2 lists, it should be A[0]<B[0]<A[1]<B[1]<...
If A[0] > B[0], vice versa.
a = [1, 10, 40]
b = [15, 30]
srcs = [a, b]
dsts = [[], []]
prev_which = -1
while all(srcs):
which = int(srcs[0][0] > srcs[1][0])
elem = srcs[which].pop(0)
if prev_which != which:
dsts[which].append(elem)
prev_which = which
for src, dst in zip(srcs,dsts):
if src:
dst.append(src.pop(0))
a, b = dsts
returns:
a = [1, 40]
b = [15]
and for
a = [3, 4, 6, 7, 8, 9]
b = [1, 2, 5, 10]
it returns [3, 6] and [1, 5, 10].
EDIT: another possibility:
import itertools as it
import operator as op
a = [3, 4, 6, 7, 8, 9]
b = [1, 2, 5, 10]
srcs = [a, b]
dsts = [[], []]
for which, elems in it.groupby(sorted((x, i) for i in (0,1) for x in srcs[i]), key=op.itemgetter(1)):
dsts[which].append(next(elems)[0])
a, b = dsts
I came up with this before you edit. But it seems the output is not what you expect. Anyway, it might help you get on the right track:
a = range(0, 30, 3)
b = range(0, 20, 2)
a.sort()
b.sort()
A = [a[i+1] for i in range(len(a)-1) if any(a[i]<b[j]<a[i+1] for j in range(len(b)-1))]
B = [b[i+1] for i in range(len(b)-1) if any(b[i]<a[j]<b[i+1] for j in range(len(a)-1))]
result = sorted(A+B)
print a, b
print result
This is "literally" what you expressed, but the result here is not what you expect. I'll try to improve this.
So, if I am reading correctly, the desired output from your example is [1,40] and [15], yes?
If so, the following would get the right result, but I am certain there is a tighter way to do it.
a = [1, 10, 40]
b = [15, 30]
c = sorted([[e_a,'a'] for e_a in a] + [[e_b,'b'] for e_b in b])
indices = []
for i in range(len(c)-1):
if c[i][1] == c[i+1][1]:
indices.append(i+1)
for e in sorted(indices, reverse=True):
del c[e]
a,b = [e[0] for e in c if e[1]=='a'],[e[0] for e in c if e[1]=='b']
First - Merging the lists and sorting them, while keeping track of which list they came from.
Second - Then remove all instances where the next item in the merged list is from the same source list.
Third - updating a and b.
I knew using the bisect module could be a good solution:
>>> def sort_relative(L1, L2):
# Switch if needed
if L1[0] > L2[0]:
L1, L2 = L2, L1
i = 0
while i + 1 < max(len(L1), len(L2)):
try:
# We know that L1[i] < L2[i]
# Get indexes where L2[i] and L2[i + 1] should be inserted
i11 = bisect.bisect_left(L1, L2[i])
i12 = bisect.bisect_left(L1, L2[i + 1])
# This condition allows to know if one element of L1
# was found between L2[i] and L2[i + 1]:
# - if so, we have L1[i] < L2[i] < L1[i + 1] < L2[i + 1]
# - else we have L1[i] < L2[i] < L1[i + 1] but
# we don't know between L1[i + 1] and L2[i + 1]
if L1[i11] < L2[i + 1]:
L1 = L1[:i + 1] + [L1[i11]] + L1[i12:]
index1, index2 = i + 1, i + 2
else:
L1 = L1[:i + 1] + L1[i12:]
index1, index2 = i, i + 1
# Do the same kind of symetric search,
# with indexes computed above
i21 = bisect.bisect_left(L2, L1[index1])
i22 = bisect.bisect_left(L2, L1[index2])
if L2[i21] < L1[index2]:
L2 = L2[:index1] + [L2[i21]] + L2[i22:]
else:
L2 = L2[:index1] + L2[i22:]
# Little trick not to test indexes everywhere:
# lists are browsed at the same time
except IndexError:
pass
# Next index !
i += 1
# Show result
print 'L1:', L1, '- L2:', L2
>>> sort_relative([1, 10, 50], [15, 30])
L1: [1, 50] - L2: [15]
>>> sort_relative([17, 18, 50], [15, 30])
L1: [15, 30] - L2: [17, 50]
>>> sort_relative([1, 10, 12, 25, 27, 50], [15, 30, 70])
L1: [1, 25, 50] - L2: [15, 30, 70]
>>> sort_relative([1, 10, 12, 25, 27, 50], [15, 30, 34, 70])
L1: [1, 25, 50] - L2: [15, 30, 70]
>>>
I didn't take into account the case when a number is both in A and B.