Related
I'm trying to figure out create nxn matrix with values range from 0 to n^2.
There must be no sequence in the row and column, except for n < 5.
Here's an example of the exected output:
array([[ 8, 13, 39, 1, 22, 37, 2],
[ 6, 26, 36, 3, 29, 35, 16],
[18, 20, 46, 28, 15, 12, 43],
[ 7, 24, 14, 41, 32, 21, 27],
[34, 31, 9, 44, 30, 48, 45],
[11, 33, 40, 10, 38, 0, 5],
[17, 23, 4, 19, 25, 47, 42]])
Create your values, select randomly without replaced (or use shuffle) and reshape the array.
import numpy as np
# dimension
n = 5
values = np.arange(0, n**2)
# randomly selected (or use shuffle)
selected = np.random.choice(values, size = n * n, replace = False)
# reshape array to matrix
matrix = np.reshape(selected, (n, n))
array([[21, 5, 12, 23, 4],
[13, 10, 19, 22, 20],
[ 7, 2, 15, 18, 17],
[ 0, 16, 6, 8, 24],
[11, 1, 9, 14, 3]])
That's a possible solution:
import random
import pprint
number_rows_columns = 5
number_list = [i for i in range(number_rows_columns**2)]
final_matrix = []
for row in range(number_rows_columns):
new_column = []
for column in range(number_rows_columns):
new_column.append(random.choice(number_list))
number_list.remove(new_column[-1])
final_matrix.append(new_column)
pprint.pprint(final_matrix)
A sample output of this code:
[[6, 13, 10, 20, 24],
[2, 14, 16, 21, 19],
[0, 8, 17, 15, 5],
[3, 18, 7, 12, 23],
[22, 1, 4, 9, 11]]
UPDATE: to remove the "sequencing" problem, this is a possible solution:
import random
import pprint
number_rows_columns = 20
matrix_is_valid = False
def fill_matrix():
number_list = [i for i in range(number_rows_columns**2)]
matrix = []
for row in range(number_rows_columns):
new_column = []
for column in range(number_rows_columns):
new_column.append(random.choice(number_list))
number_list.remove(new_column[-1])
matrix.append(new_column)
return matrix
def check_rows(matrix):
global matrix_is_valid
for row in matrix:
for index, element in enumerate(row[:-1]):
if abs(element - row[index + 1]) == 1:
matrix_is_valid = False
return
def check_matrix(matrix):
global matrix_is_valid
matrix_is_valid = True
check_rows(matrix)
if not matrix_is_valid:
return
matrix = list(list(a) for a in zip(*matrix))
check_rows(matrix)
while not matrix_is_valid:
final_matrix = fill_matrix()
check_matrix(final_matrix)
pprint.pprint(final_matrix)
IMPORTANT: I would like to specify that this is NOT an efficient solution. Basically this algorithm create a matrix, check that each row and column (by transposition) has no numbers "sequencing", and if there are any, create a new matrix and check that until he gets a valid one.
This is an algorithm that has an average time complexity of O((n+1)!), see Bogosort to deepen.
UPDATE IMPROVED VERSION: This improved version check the validity of each number insertion, so, the matrix must be rebuilt from scratch only if and when the last number cannot be entered
The code:
import random
import pprint
number_rows_columns = 12
matrix_is_valid = False
counter = 0
def fill_matrix():
global matrix_is_valid
matrix_is_valid = True
number_list = [i for i in range(number_rows_columns**2)]
matrix = []
for row in range(number_rows_columns):
new_column = []
for column in range(number_rows_columns):
new_column.append(random.choice(number_list))
if (column > 0 or row > 0) and len(number_list) > 1:
invalid_value = True
if column != 0 and row != 0:
while abs(new_column[-1] - new_column[-2]) == 1 or abs(new_column[-1] - matrix[-1][column]) == 1:
new_column[-1] = random.choice(number_list)
elif column != 0 and row == 0:
while abs(new_column[-1] - new_column[-2]) == 1:
new_column[-1] = random.choice(number_list)
elif column == 0 and row != 0:
while abs(new_column[-1] - matrix[-1][column]) == 1:
new_column[-1] = random.choice(number_list)
number_list.remove(new_column[-1])
matrix.append(new_column)
if abs(matrix[-1][-1] - matrix[-1][-2]) == 1 or abs(matrix[-1][-1] - matrix[-2][-1]) == 1:
matrix_is_valid = False
return matrix
while not matrix_is_valid:
final_matrix = fill_matrix()
pprint.pprint(final_matrix)
I'm trying to find the number that I'm looking from in a 2D array list. However, it has to be sorted first before searching.
Everything seems to be working fine when I'm trying to find a number in the 2D array. It is just the fact of sorting the 2D array in a way that will still be working. Let's assume I want to sort a 3x3 2D array. The way that it should display is:
[[8, 27, 6],
[1, 0, 11],
[10, 9, 3]]
Then, I will be looking for a number by using the binary search method through the sorted 2D array. My mid value will be in the middle of the array from the search.
This is just an example, but what I want to accomplish when I put randomized numbers and then sort row and columns. Using this idea, I'm using the random.randint() library from Python to randomized my numbers. Then, I'm trying to sort afterward in my 2d array, but it isn't really sorting before continuing.
n = 5
m = 5
def findnum_arr(array, num):
low = 0
high = n * m - 1
while (high >= low):
mid = (low + high) // 2
i = mid // m
j = mid % m
if (num == array[i][j]):
return True
if (num < array[i][j]):
high = mid - 1
else:
low = mid + 1
return False
if __name__ == '__main__':
multi_array = [[random.randint(0, 20) for x in range(n)] for y in range(m)]
sorted(multi_array)
Sorted:
[[0, 1, 3],
[6, 8, 9],
[10, 11, 27]]
Should be the sorted 2D array. Is it possible that both the row and column are sorted respectively with the sorted function?
Calling sorted on a nested list that is just going to sort based on the first index in the list.
Example:
arr = [[8, 27, 6],[1, 0, 11],[10, 15, 3], [16, 12, 14], [4, 9, 13]]
is going to return
[[1, 0, 11], [4, 9, 13], [8, 27, 6], [10, 15, 3], [16, 12, 14]]
To do this way that you want, you are going to have to flatten and then reshape.
To do this, I would try introducing numpy.
import numpy as np
a = np.array(sorted(sum(arr, [])))
#sorted(sum(arr, [])) flattens the list
b = np.reshape(a, (-1,3)).tolist()
EDITED FOR CLARITY: You can use your m and n as parameters in np.reshape. The first parameter (m) would return the number of arrays, while (n) would return the number of arrays.
The use of -1 in either parameter means that the reshaped array will be fit to return the requirements of the other parameter.
b would return
[[0, 1, 3], [4, 6, 8], [9, 10, 11], [12, 13, 14], [15, 16, 27]]
Finally found out a proper solution without using numpy and avoiding sum() module.
if __name__ == '__main__':
x = 7
multi_array = [[random.randint(0, 200) for x in range(n)] for y in range(m)]
# one_array = sorted(list(itertools.chain.from_iterable(multi_array))) Another way if you are using itertools
one_array = sorted([x for row in multi_array for x in row])
sorted_2d = [one_array[i:i+m] for i in range(0, len(one_array), n)]
print("multi_array list is: \n{0}\n".format(multi_array))
print("sorted 2D array: \n{0}\n".format(sorted_2d))
if not findnum_arr(sorted_2d, x):
print("Not Found")
else:
print("Found")
output:
multi_array list is:
[[40, 107, 23, 27, 42], [150, 84, 108, 191, 172], [154, 22, 161, 26, 31], [18, 150, 197, 77, 191], [96, 124, 81, 1
25, 186]]
sorted 2D array:
[[18, 22, 23, 26, 27], [31, 40, 42, 77, 81], [84, 96, 107, 108, 124], [125, 150, 150, 154, 161], [172, 186, 191, 1
91, 197]]
Not Found
I wanted to find a standard library module where I could flat the 2D array into 1D and sort it. Then, I would make a list comprehension of my 1D array and build it into a 2D array to. This sounds a lot of works but seems to work fine. Let me know if there is a better way to do it without numpy and faster :)
How do I count the number of times the same integer occurs?
My code so far:
def searchAlgorithm (target, array):
i = 0 #iterating through elements of target list
q = 0 #iterating through lists sublists via indexes
while q < 4:
x = 0 #counting number of matches
for i in target:
if i in array[q]:
x += 1
else:
x == 0
print(x)
q += 1
a = [8, 12, 14, 26, 27, 28]
b = [[4, 12, 17, 26, 30, 45], [8, 12, 19, 24, 33, 47], [3, 10, 14, 31, 39, 41], [4, 12, 14, 26, 30, 45]]
searchAlgorithm(a, b)
The output of this is:
2
2
1
3
What I want to achieve is counting the number of times '1', '2' '3' matches occurs.
I have tried:
v = 0
if searchAlgorithm(a, b) == 2:
v += 1
print(v)
But that results in 0
You can use intersection of sets to find elements that are common in both lists. Then you can get the length of the sets. Here is how it looks:
num_common_elements = (len(set(a).intersection(i)) for i in b)
You can then iterate over the generator num_common_elements to use the values. Or you can cast it to a list to see the results:
print(list(num_common_elements))
[Out]: [2, 2, 1, 3]
If you want to implement the intersection functionality yourself, you can use the sum method to implement your own version. This is equivalent to doing len(set(x).intersection(set(y))
sum(i in y for i in x)
This works because it generates values such as [True, False, False, True, True] representing where the values in the first list are present in the second list. The sum method then treats the Trues as 1s and Falses as 0s, thus giving you the size of the intersection set
This is based on what I understand from your question. Probably you are looking for this:
from collections import Counter
def searchAlgorithm (target, array):
i = 0 #iterating through elements of target list
q = 0 #iterating through lists sublists via indexes
lst = []
while q < 4:
x = 0 #counting number of matches
for i in target:
if i in array[q]:
x += 1
else:
x == 0
lst.append(x)
q += 1
print(Counter(lst))
a = [8, 12, 14, 26, 27, 28]
b = [[4, 12, 17, 26, 30, 45], [8, 12, 19, 24, 33, 47], [3, 10, 14, 31, 39, 41], [4, 12, 14, 26, 30, 45]]
searchAlgorithm(a, b)
# Counter({2: 2, 1: 1, 3: 1})
Thanks to some for their helpful feedback, I have since come up a more simplified solution that does exactly what I want.
By storing the results of the matches in a list, I can then return the list out of the searchAlgorithm function and simple use .count() to count all the matches of a specific number within the list.
def searchAlgorithm (target, array):
i = 0
q = 0
results = []
while q < 4:
x = 0 #counting number of matches
for i in target:
if i in array[q]:
x += 1
else:
x == 0
results.append(x)
q += 1
return results
a = [8, 12, 14, 26, 27, 28]
b = [[4, 12, 17, 26, 30, 45], [8, 12, 19, 24, 33, 47], [3, 10, 14, 31, 39, 41], [4, 12, 14, 26, 30, 45]]
searchAlgorithm(a, b)
d2 = (searchAlgorithm(winNum, lotto).count(2))
Have the following code:
import sys
ints = [1,2,3,4,5,6,8,9,10,11,14,34,14,35,16,18,39,10,29,30,14,26,64,27,48,65]
ints.sort()
ints = list(set(ints))
c = {}
for i,v in enumerate(ints):
if i+1 >= len(ints):
continue
if ints[i+1] == v + 1 or ints[i-1] == v - 1:
if len(c) == 0:
c[v] = [v]
c[v].append(ints[i+1])
else:
added=False
for x,e in c.items():
last = e[-1]
if v in e:
added=True
break
if v - last == 1:
c[x].append(v)
added=True
if added==False:
c[v] = [v]
else:
if v not in c:
c[v] = [v]
print('input ', ints)
print('output ', c))
The objective:
Given a list of integers, create a dictionary that contains consecutive integers grouped together to reduce the overall length of the list.
Here is output from my current solution:
input [1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 14, 16, 18, 26, 27, 29, 30, 34, 35, 39, 48, 64, 65]
output {1: [1, 2, 3, 4, 5, 6], 8: [8, 9, 10, 11], 14: [14], 16: [16], 18: [18], 26: [26, 27], 29: [29, 30], 34: [34, 35], 39: [39], 48: [48], 64: [64]}
Conditions/constraints:
If the current integer is either a) in an existing list or b) is the last item in an existing list, we don't want to create another list for this item.
i.e. in the range 1-5 inclusive, when we get to 3, don't create a list 3,4, instead append 3 to the existing list [1,2]
My current iteration works fine, but it gets exponentially slower the bigger the list is because of the for x,e in c.items() existing list check.
How can I make this faster while still achieving the same result?
New solution (from 13 seconds to 0.03 seconds using an input list of 19,000 integers):
c = {}
i = 0
last_list = None
while i < len(ints):
cur = ints[i]
if last_list is None:
c[cur] = [cur]
last_list = c[cur]
else:
if last_list[-1] == cur-1:
last_list.append(cur)
else:
c[cur] = [cur]
last_list = c[cur]
i += 1
As you have lists of consecutive numbers, I suggest you to use range objects instead of lists:
d, head = {}, None
for x in l:
if head is None or x != d[head].stop:
head = x
d[head] = range(head, x+1)
The solution is simple if you use a for loop and just keep track of your current list. Don't forget to make a new list when you find a gap:
result = {}
cl = None
for i in ints:
if cl is None or i - 1 != cl[-1]:
cl = result.setdefault(i, [])
cl.append(i)
There is a great library called more_itertools which has a method called: consecutive_groups():
import more_itertools as mit
x = [1,2,3,4,5,6,8,9,10,11,14,34,14,35,16,18,39,10,29,30,14,26,64,27,48,65]
x = [list(j) for j in mit.consecutive_groups(sorted(list(set(x))))]
# [[1, 2, 3, 4, 5, 6], [8, 9, 10, 11], [14], [16], [18], [26, 27], [29, 30], [34, 35], [39], [48], [64, 65]]
dct_x = {i[0]: i for i in x}
print(dct_x)
Output:
{1: [1, 2, 3, 4, 5, 6], 8: [8, 9, 10, 11], 14: [14], 16: [16], 18: [18], 26: [26, 27], 29: [29, 30], 34: [34, 35], 39: [39], 48: [48], 64: [64, 65]}
One more comment, you want to sort after converting to and from a set, since sets are unordered.
One can solve this task in O(n) (linear) complexity. Just keep it simple:
integers = [1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 14, 16, 18, 26, 27, 29, 30, 34, 35, 39, 48, 64, 65]
helper = []
counter = 0
while counter < len(integers):
if not helper or helper[-1] + 1 != integers[counter]:
print('gap found', integers[counter]) # do your logic
helper.append(integers[counter])
counter += 1
The algorithm above assumes that the input list is already sorted. It gives us a huge advantage. At the same time one can sort the list of integers explicitly before running this algorithm. The total complexity of the solution will be then: O(n * log n) + O(n) which is efficiently O(n * log n). And O(n * log n) is the complexity of the sorting procedure.
I would kindly suggest to remember this extremely useful trick of using sorting before approaching a task for future usages.
Here's a simple implementation that achieves what you are after, using list slicing:
integers = [1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 14, 16, 18, 26, 27, 29, 30, 34, 35, 39, 48, 64, 65]
for i, integer in enumerate(integers):
if i == 0:
out_dict = {}
start = 0
else:
if integer != prev_integer + 1:
out_dict[integers[start]] = integers[start:i]
start = i
if i == len(integers) - 1:
out_dict[integers[start]] = integers[start:]
prev_integer = integer
>>>out_dict = {1: [1, 2, 3, 4, 5, 6], 8: [8, 9, 10, 11], 14: [14], 16: [16], 18: [18], 26: [26, 27], 29: [29, 30], 34: [34, 35], 39: [39], 48: [48], 64: [64]}
Note: The dictionary will likely not be sorted by ascending keys, as dict types are not ordered.
You can try with itertools , But i would like to try recursion :
input_dta=[1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 14, 16, 18, 26, 27, 29, 30, 34, 35, 39, 48, 64, 65]
final_=[]
def consecutives(data):
sub_final=[]
if not data:
return 0
else:
for i,j in enumerate(data):
try:
if abs(data[i]-data[i+1])==1:
sub_final.extend([data[i],data[i+1]])
else:
if sub_final:
final_.append(set(sub_final))
return consecutives(data[i+1:])
except IndexError:
pass
final_.append(set(sub_final))
consecutives(input_dta)
print(final_)
output:
[{1, 2, 3, 4, 5, 6}, {8, 9, 10, 11}, {26, 27}, {29, 30}, {34, 35}, {64, 65}]
I'd like to produce a function like split(arr, i, j), which divides array arr by axis i, j?
But I do not know how to do it. In the following method using array_split. It is impossible for me to obtain the two-dimensional array that we are seeking by merely dividing N-dimensional arrays into N-1 dimensional arrays.
import numpy as np
arr = np.arange(36).reshape(4,9)
dim = arr.ndim
ax = np.arange(dim)
arritr = [np.array_split(arr, arr.shape[ax[i]], ax[i]) for i in range(dim)]
print(arritr[0])
print(arritr[1])
How can I achieve this?
I believe you would like to slice array by axis(row, column). Here is the doc. https://docs.scipy.org/doc/numpy/reference/arrays.indexing.html
arr[1,:] # will return all values at index 1(row index 1)
arr[:,1] # will return all values at column 1
I'm guessing a bit here, but it sounds like you want to divide the array into 4 blocks.
In [120]: arr = np.arange(36).reshape(6,6)
In [122]: [arr[:3,:4], arr[:3:,4:], arr[3:, :4], arr[3:,4:]]
Out[122]:
[array([[ 0, 1, 2, 3],
[ 6, 7, 8, 9],
[12, 13, 14, 15]]),
array([[ 4, 5],
[10, 11],
[16, 17]]),
array([[18, 19, 20, 21],
[24, 25, 26, 27],
[30, 31, 32, 33]]),
array([[22, 23],
[28, 29],
[34, 35]])]
Don't worry about efficiency. array_split does the same sort of slicing. Check its code to verify that.
If you want more slices, you could add more arr[i1:i2, j1:j2], for any mix of indices.
Are you looking for something like matlab's mat2cell? Then you could do:
import numpy as np
def ndsplit(a, splits):
assert len(splits) <= a.ndim
splits = [np.r_[0, s, m] for s, m in zip(splits, a.shape)]
return np.frompyfunc(lambda *x: a[tuple(slice(s[i],s[i+1]) for s, i in zip(splits, x))], len(splits), 1)(*np.indices(tuple(len(s) - 1 for s in splits)))
# demo
a = np.arange(56).reshape(7, 8)
print(ndsplit(a, [(2, 4), (1, 5, 6)]))
# [[array([[0],
# [8]])
# array([[ 1, 2, 3, 4],
# [ 9, 10, 11, 12]])
# array([[ 5],
# [13]]) array([[ 6, 7],
# [14, 15]])]
# [array([[16],
# [24]])
# array([[17, 18, 19, 20],
# [25, 26, 27, 28]])
# array([[21],
# [29]]) array([[22, 23],
# [30, 31]])]
# [array([[32],
# [40],
# [48]])
# array([[33, 34, 35, 36],
# [41, 42, 43, 44],
# [49, 50, 51, 52]])
# array([[37],
# [45],
# [53]])
# array([[38, 39],
# [46, 47],
# [54, 55]])]]