Related
Let say I have an array of
x = [[5, 9, 7, 17, 13, 0], [8, 10, 16, 35, 7, 5], [10, 17, 5]]
I want to sort the value so that it will look like this:
x = [[0, 5, 5, 5, 7, 7], [8, 9, 10, 10, 13, 16], [17, 17, 35]]
How could I achieve this?
code:
x = [[5, 9, 7, 17, 13, 0], [8, 10, 16, 35, 7, 5], [10, 17, 5]]
y = sorted(sum([i for i in x],[]))
result = []
for i in x:
temp = []
for j in range(len(i)):
temp.append(y.pop(0))
result.append(temp)
print(result)
result:
[[0, 5, 5, 5, 7, 7], [8, 9, 10, 10, 13, 16], [17, 17, 35]]
The best answer is given by #leaf_yakitori please look at it. Now I just added this code to reduce time complexity from O(n^2) to O(n)
x = [[5, 9, 7, 17, 13, 0], [8, 10, 16, 35, 7, 5], [10, 17, 5]]
y = sorted(sum([i for i in x],[]))
result = []
ind = 0
for i in x:
result.append(y[ind:ind + len(i)])
ind += len(i)
print(result)
lets say i have a list of random numbers
randomlist = [9, 8, 18, 1, 17, 3, 13, 4, 13, 1, 9, 10, 7, 13, 3, 9, 13, 10, 18, 10, 19, 3, 14, 14, 19, 4, 20, 17, 8, 17, 3, 12, 8, 12, 1, 2, 15, 13, 2, 8, 18, 10, 14, 11, 17, 11, 2, 7, 4, 7, 5, 5, 18, 7, 11, 13, 20, 9, 2, 14, 19, 1, 16, 10, 16, 19, 13, 19, 11, 17, 8, 2, 10, 16, 5, 14, 7, 11, 17, 9, 9, 6, 12, 6, 12, 4, 14, 10, 2, 6, 9, 1, 14, 4, 14, 13, 18, 13, 6, 8]
There are three categorys of numbers:
numbers which are divisible by two (2,4,6,8,10,12,14,16,18,20)
prime numbers except two (3,7,11,13,17,19)
rest (1,5,9,15)
Now what i want to do is the following:
I will go through the list and whenever a number of the rest category occurs i want to create a list like this [ %2 , prime] whereas the elements are the ones which occured most recently in the list. The goal is to have a lists of lists with two elements. I hope its clear what im trying to do. Here is my code:
randomlist = [9, 8, 18, 1, 17, 3, 13, 4, 13, 1, 9, 10, 7, 13, 3, 9, 13, 10, 18, 10, 19, 3, 14, 14, 19, 4, 20, 17, 8, 17, 3, 12, 8, 12, 1, 2, 15, 13, 2, 8, 18, 10, 14, 11, 17, 11, 2, 7, 4, 7, 5, 5, 18, 7, 11, 13, 20, 9, 2, 14, 19, 1, 16, 10, 16, 19, 13, 19, 11, 17, 8, 2, 10, 16, 5, 14, 7, 11, 17, 9, 9, 6, 12, 6, 12, 4, 14, 10, 2, 6, 9, 1, 14, 4, 14, 13, 18, 13, 6, 8]
def check_prime(x):
for i in range(2, x):
if (x % i) == 0:
return False
else:
return True
def check_number(x):
if x%2 == 0:
return "zweier"
elif check_prime(x) == True:
return "prim"
else:
return "rest"
final_list = []
partial_list = [0,0]
for x in randomlist:
if check_number(x) =="zweier":
partial_list[0] = x
elif check_number(x) == "rest":
partial_list[1] = x
else:
final_list.append(partial_list)
for x in final_list:
print(x)
Ouput:
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
[8, 9]
What confuses me very much is that if i print the final_list members right after creating them it shows the right solution:
randomlist = [9, 8, 18, 1, 17, 3, 13, 4, 13, 1, 9, 10, 7, 13, 3, 9, 13, 10, 18, 10, 19, 3, 14, 14, 19, 4, 20, 17, 8, 17, 3, 12, 8, 12, 1, 2, 15, 13, 2, 8, 18, 10, 14, 11, 17, 11, 2, 7, 4, 7, 5, 5, 18, 7, 11, 13, 20, 9, 2, 14, 19, 1, 16, 10, 16, 19, 13, 19, 11, 17, 8, 2, 10, 16, 5, 14, 7, 11, 17, 9, 9, 6, 12, 6, 12, 4, 14, 10, 2, 6, 9, 1, 14, 4, 14, 13, 18, 13, 6, 8]
def check_prime(x):
for i in range(2, x):
if (x % i) == 0:
return False
else:
return True
def check_number(x):
if x%2 == 0:
return "zweier"
elif check_prime(x) == True:
return "prim"
else:
return "rest"
final_list = []
partial_list = [0,0]
for x in randomlist:
if check_number(x) =="zweier":
partial_list[0] = x
elif check_number(x) == "rest":
partial_list[1] = x
else:
final_list.append(partial_list)
print(final_list[-1])
Output:
[18, 9]
[18, 9]
[18, 9]
[18, 9]
[4, 9]
[4, 9]
[10, 9]
[10, 9]
[10, 9]
[10, 9]
[10, 9]
[10, 9]
[14, 9]
[20, 9]
[8, 9]
[8, 9]
[12, 9]
[2, 15]
[14, 15]
[14, 15]
[14, 15]
[2, 15]
[4, 15]
[4, 15]
[4, 15]
[18, 15]
[18, 15]
[18, 15]
[14, 9]
[14, 9]
[16, 9]
[16, 9]
[16, 9]
[16, 9]
[16, 9]
[16, 9]
[14, 9]
[14, 9]
[14, 9]
[6, 9]
[14, 9]
[18, 9]
So it seems like the basis idea is okay. I tried very much but i just cant find out what i am doing wrong. Thanks very much for help !
This will give you the desired results. Refer to here that explains what is happening.
randomlist = [9, 8, 18, 1, 17, 3, 13, 4, 13, 1, 9, 10, 7, 13, 3, 9, 13, 10, 18, 10, 19, 3, 14, 14, 19, 4, 20, 17, 8, 17, 3, 12, 8, 12, 1, 2, 15, 13, 2, 8, 18, 10, 14, 11, 17, 11, 2, 7, 4, 7, 5, 5, 18, 7, 11, 13, 20, 9, 2, 14, 19, 1, 16, 10, 16, 19, 13, 19, 11, 17, 8, 2, 10, 16, 5, 14, 7, 11, 17, 9, 9, 6, 12, 6, 12, 4, 14, 10, 2, 6, 9, 1, 14, 4, 14, 13, 18, 13, 6, 8]
def check_prime(x):
for i in range(2, x):
if (x % i) == 0:
return False
else:
return True
def check_number(x):
if x%2 == 0:
return "zweier"
elif check_prime(x) == True:
return "prim"
else:
return "rest"
final_list = []
partial_list = [0,0]
for x in randomlist:
if check_number(x) =="zweier":
partial_list[0] = x
elif check_number(x) == "rest":
partial_list[1] = x
else:
final_list.append(partial_list.copy())
for x in final_list:
print(x)
The reason for this is that when you iterate over the items in your randomlist and append partial_list to final_list, what you append is a reference to the same object (partial_list), but not the values contained.
If you change the append statement to be like:
final_list.append(partial_list.copy())
Will every time append a copy of the partial_list and your code will eventually print correct result.
Therefore your code would be:
def check_prime(x):
for i in range(2, x):
if (x % i) == 0:
return False
else:
return True
def check_number(x):
if x%2 == 0:
return "zweier"
elif check_prime(x) == True:
return "prim"
else:
return "rest"
final_list = []
partial_list = [0,0]
for x in randomlist:
if check_number(x) =="zweier":
partial_list[0] = x
elif check_number(x) == "rest":
partial_list[1] = x
else:
final_list.append(partial_list.copy())
for x in final_list:
print(x)
I am trying to print the diagonal numbers of this matrix so that I get [5, 9, 13, 17, 21].
I've tried changing the variables in the for loop.
matrix = [[ 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10],
[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20],
[21, 22, 23, 24, 25]]
diagonal = []
last_column = len(matrix[0]) - 1
for row in matrix:
diagonal.append([row][0][4])
print(diagonal)
Instead of getting the diagonal numbers, I get [5, 10, 15, 20, 25].
You can also use numpy.diagonal
import numpy
matrix = [[ 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10],
[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20],
[21, 22, 23, 24, 25]]
arr=numpy.array(matrix)
print(numpy.fliplr(arr).diagonal())
Outputs:
[ 5 9 13 17 21]
To get the diagonal use print(arr.diagonal())
You want the anti-diagonal, so you can use a simple list comprehension (assuming matrix is square).
[matrix[i][-(i+1)] for i in range(len(matrix))]
# [5, 9, 13, 17, 21]
I have a list of ints in python, and I would like the output to be a list of different "craters" in the sequence. I define a crater as a sequence of numbers that begins with descending ints that gradually grow bigger, until they reach a number that is equal to the first int of the crater or greater than the first int in the crater.
If the last number is equal or smaller than the first - it should be in the output at the end of the crater. If the last number is greater than the first number in the crater - it should not be appended to the end of the output list.
For example, for the list:
1,2,3,4,5,6,5,4,3,4,5,6,7,8,9
A "crater" would be:
6,5,4,3,4,5,6
My code:
def find_crater(my_list):
cur_crater = []
for i in range(len(my_list)-1):
#check if the numbers are decreasing
if (my_list[i] - my_list[i+1] > 0):
cur_crater.append(my_list[i])
#if increasing - check if we're in a crater
#and if current number is smaller than begining of crater
elif len(cur_crater) > 1 and my_list[i] <= cur_crater[0]:
cur_crater.append(my_list[i])
#print crater and empty list
elif len(cur_crater) > 1 and my_list[i+1] > cur_crater[0]:
print(cur_crater)
cur_crater = []
#continue if we're out of a crater
else:
continue
#catching the last crater in the list
if len(cur_crater) > 1:
#include last int
if my_list[i] - my_list[-1] < 0 and my_list[-1] <= cur_crater[0]:
cur_crater.append(my_list[-1])
print(cur_crater)
return
I have called the function on 2 lists. The 1st output is as expected:
ok_list = [12, 4, 7, 4, 2, 4, 5, 6, 5, 12, 21, 23,
24, 26, 25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14,
17, 27, 28, 19, 17, 19, 21, 19, 12, 23, 25, 27]
Ok list output [edit: not so ok - it ommited the first '4' so turns out it's not so OK after all]:
[12, 7, 4, 2, 4, 5, 6, 5, 12]
[26, 25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14, 17]
[28, 19, 17, 19, 21, 19, 12, 23, 25, 27]
However, the second list combines 2 lists of craters into 1 list in the output:
problematic = [12, 4, 7, 4, 2, 4, 5, 6, 5, 12, 21, 23,
24, 26, 25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14,
17, 27, 19, 25, 19, 12, 23, 25, 27]
problematic Output:
[12, 7, 4, 2, 4, 5, 6, 5, 12]
[26, 25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14, 17, 27, 19, 25, 19, 12, 23, 25]
I was expecting:
[12, 4, 7, 4, 2, 4, 5, 6, 5, 12]
[26, 25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14, 17]
[27, 19, 25, 19, 12, 23, 25, 27]
I tried to take care of this by writing:
my_list[i+1] > cur_crater[0]
and thus checking the size of next int in the list - but that does not seem to fix it [I left it in the code even though it does not do the trick in hopes of someone explaining why is that wrong/ not working?].
In conclusion, my code can't handle it when there is a crater right after a crater with only one int in between.
If the input is:
[12, 4, 7, 4, 2, 4, 5, 6, 5, 12, 21, 10, 9, 8, 6, 9, 10]
Then the output is one long list, but I'd like to split it after list item 12 and before list item 21, but the output is one long list.
I would love to get info about any library or method that can give me more ideas regarding a better and more efficient solution.
Presuming your expected output is wrong which it seems to be, all you want to do is go until you find an element >= to the start of the chain and catch chains that only contain a single element:
def craters(lst):
it = iter(lst)
# get start of first chain
first = next(it)
tmp = [first]
# iterate over the remaining
for ele in it:
# >= ends chain
if ele >= first:
# if equal, add it and call
# next(it) to set the next first element.
if ele == first:
tmp.append(ele)
yield tmp
first = next(it)
tmp = [first]
# else yield the group if it has > 1 element.
# if it has 1 element it is not a descending start sequecne
else:
if len(tmp) > 1:
yield tmp
tmp = [ele]
first = ele
else:
tmp.append(ele)
if len(tmp) > 1: # catch single element last
yield tmp
Output:
In [5]: ok_list = [12, 4, 7, 4, 2, 4, 5, 6, 5, 12, 21, 23,
...: 24, 26, 25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14,
...: 17, 27, 28, 19, 17, 19, 21, 19, 12, 23, 25, 27]
In [6]: problematic = [12, 4, 7, 4, 2, 4, 5, 6, 5, 12, 21, 23,
...: 24, 26, 25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14,
...: 17, 27, 19, 25, 19, 12, 23, 25, 27]
In [7]: ex_ok = [[12, 4, 7, 4, 2, 4, 5, 6, 5, 12],
...: [26, 25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14, 17],
...: [28, 19, 17, 19, 21, 19, 12, 23, 25, 27]]
In [8]: ex_p = [[12,4, 7, 4, 2, 4, 5, 6, 5, 12],
...: [26, 25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14, 17],
...: [27, 19, 25, 19, 12, 23, 25, 27]]
In [9]: print(list(craters(problematic)) == ex_p)
True
In [10]: print(list(craters(ok_list)) == ex_ok)
True
In [11]: print(list(craters([12, 4, 7, 4, 2, 4, 5, 6, 5, 12, 21, 10, 9, 8, 6, 9, 10])))
[[12, 4, 7, 4, 2, 4, 5, 6, 5, 12], [21, 10, 9, 8, 6, 9, 10]]
In [12]: list(craters([1, 2, 3, 4, 5, 6, 5, 4, 3, 4, 5, 6, 7, 8, 9]))
Out[13]: [[6, 5, 4, 3, 4, 5, 6]]
That does not involve any slicing/indexing you can lazily return each group.
To simplify your algorithm, the steps are:
Start with the first element, then check if the next element is >=, if it is and it is equal add it to the group, if it is > set that to be the new start of the group.
If the new first is not greater than the next element the length of that group will be one as it does not satisfy sequence of numbers that begins with descending. So we keep consuming and setting the next element to be the first element of the sequence until we find one the is > the next element, that is what the call to next(it) is doing then we just need to wash and repeat.
Here is what I came with:
def find_crater(my_list):
previous = None
current_crater = []
crater_list = []
for elem in my_list:
#For the first element
if not previous:
previous = elem
continue
if len(current_crater) == 0:
if elem > previous:
previous = elem
else:
current_crater.append(previous)
previous = elem
else:
if elem > current_crater[0]:
current_crater.append(previous)
crater_list.append(current_crater)
current_crater = []
previous = elem
else:
current_crater.append(previous)
previous = elem
if len(current_crater) != 0:
if elem > current_crater[0]:
current_crater.append(previous)
crater_list.append(current_crater)
else:
current_crater.append(previous)
crater_list.append(current_crater)
return crater_list
That gave me the exact output you want:
In [5]: ok_list = [12, 4, 7, 4, 2, 4, 5, 6, 5, 12, 21, 23,
...: 24, 26, 25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14,
...: 17, 27, 28, 19, 17, 19, 21, 19, 12, 23, 25, 27]
In [6]: find_crater(ok_list)
Out[6]:
[[12, 4, 7, 4, 2, 4, 5, 6, 5, 12],
[26, 25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14, 17],
[28, 19, 17, 19, 21, 19, 12, 23, 25, 27]]
In [7]: problematic = [12, 4, 7, 4, 2, 4, 5, 6, 5, 12, 21, 23,
...: 24, 26, 25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14,
...: 17, 27, 19, 25, 19, 12, 23, 25, 27]
In [8]: find_crater(problematic)
Out[8]:
[[12, 4, 7, 4, 2, 4, 5, 6, 5, 12],
[26, 25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14, 17],
[27, 19, 25, 19, 12, 23, 25, 27]]
Try this:
We just slice the list finding start_index:end_index making three cases
When element is equal
When element is greater
Boundary case when last element even if smaller may need to be sliced
def find_crater(l):
result = []
start_index = 0
for i in range( start_index +1,len(l)):
start = l[start_index]
if i==len(l)-1 and l[i]!=start:
result = l[start_index:i+1]
print result
elif l[i]==start:
end_index = i+1
result = l[start_index:end_index]
start_index = end_index +1
if len(result)>1:
print result
elif l[i]>start:
end_index = i
result = l[start_index:end_index]
start_index = end_index
if len(result)>1:
print result
Input:
ok_list = [12, 4, 7, 4, 2, 4, 5, 6, 5, 12, 21, 23,
24, 26, 25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14,
17, 27, 28, 19, 17, 19, 21, 19, 12, 23, 25, 27]
problematic = [12, 4, 7, 4, 2, 4, 5, 6, 5, 12, 21, 23,
24, 26, 25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14,
17, 27, 19, 25, 19, 12, 23, 25, 27]
Output:
find_crater(ok_list)
find_crater(problematic)
[12, 4, 7, 4, 2, 4, 5, 6, 5, 12]
[25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14, 17]
[28, 19, 17, 19, 21, 19, 12, 23, 25, 27]
[12, 4, 7, 4, 2, 4, 5, 6, 5, 12]
[25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14, 17]
[27, 19, 25, 19, 12, 23, 25, 27]
Suppose I have a list like this:
mylist = [2,3,4,7,8,9,0,1,2,3,10,11,12,20,19,18,17,17,18,19,20,21]
I want to split it into sub-lists like this:
sublist_1 = [2,3,4]
sublist_2 = [7,8,9]
sublist_3 = [0,1,2,3]
sublist_4 = [10,11,12]
sublist_5 = [20,19,18,17]
sublist_5 = [17,18,19,20,21]
How can I do this?
Code -
mylist = [2, 3, 4, 7, 8, 9, 0, 1, 2, 3, 10, 11, 12, 20, 19, 18, 17, 17, 18, 19,
20, 21]
result = []
temp_list = [mylist[0]]
for i in range(1, len(mylist)):
if abs(mylist[i] - mylist[i - 1]) != 1:
result.append(temp_list)
temp_list = [mylist[i]]
else:
temp_list.append(mylist[i])
if temp_list:
result.append(temp_list)
print(result)
Output -
[[2, 3, 4], [7, 8, 9], [0, 1, 2, 3], [10, 11, 12], [20, 19, 18, 17],
[17, 18, 19, 20, 21]]
This would do;
mylist = [2,3,4,7,8,9,0,1,2,3,10,11,12,20,19,18,17,17,18,19,20,21]
index =0
for i in range(0, len(mylist)):
#print (mylist[i+1])
if (i+1 >= len(mylist)):
print (mylist[index:i+1])
break
if not( (mylist[i+1] - mylist[i] == 1) or (mylist[i+1] - mylist[i] == -1) ):
print (mylist[index:i+1])
index = i+1
Output
[2, 3, 4]
[7, 8, 9]
[0, 1, 2, 3]
[10, 11, 12]
[20, 19, 18, 17]
[17, 18, 19, 20, 21]
This is the numpy approach. I'm using ediff1d,
intersect1d, nonzero
import numpy as np
mylist = [2, 3, 4, 7, 8, 9, 0, 1, 2, 3, 10, 11, 12, 20, 19, 18, 17, 17, 18, 19,
20, 21]
a = np.array(mylist)
t = np.ediff1d(mylist)
i = np.intersect1d(np.nonzero(t!=-1), np.nonzero(t!=1))
rslt = np.split(a,i+1)
rslt
Out[70]:
[array([2, 3, 4]),
array([7, 8, 9]),
array([0, 1, 2, 3]),
array([10, 11, 12]),
array([20, 19, 18, 17]),
array([17, 18, 19, 20, 21])]
if you want the output to be list instead of numpy array, change the last line to rslt = [x.tolist() for x in np.split(a,i+1)], the result will be
rslt
Out[9]:
[[2, 3, 4],
[7, 8, 9],
[0, 1, 2, 3],
[10, 11, 12],
[20, 19, 18, 17],
[17, 18, 19, 20, 21]]