I am having a list of lists, which is an interpretation of a matrix
For example:
1 2 3
2 3 4
5 6 7
I want to expand it to have an edge on the corners, whose values are -1
-1 -1 -1 -1 -1
-1 1 2 3 -1
-1 2 3 4 -1
-1 5 6 7 -1
-1 -1 -1 -1 -1
I have created a new list of lists, which has +2 more rows and +2 more columns
Do people have a concise mathematical formula for a one-line if statement for determining whether an element is at the 'edge'.
I tried
i*j == 0
But it only fills in the left part of the corner.
I know this could simply be done with two if statements, but I ask this question out of the curiosity
I like the modulo above. Or you could take advantage of Python's any operator
any([i==0, i==len(mat)-1, j==0, j==len(mat[0])-1])
Given inputs
n = 3
m = [
[1, 2, 3],
[2, 3, 4],
[5, 6, 7]
]
a simple approach would be something like
p = [[-1] * (n+2), *([-1] + r + [-1] for r in m), [-1] * (n+2)]
which gives
[[-1, -1, -1, -1, -1],
[-1, 1, 2, 3, -1],
[-1, 2, 3, 4, -1],
[-1, 5, 6, 7, -1],
[-1, -1, -1, -1, -1]]
but if you want to form it from indexes (i and j), then you could use a compound boolean condition
[[-1 if not (i and j) or not(n+1-i and n+1-j) else m[i-1][j-1] for j in range(n+2)] for i in range(n+2)]
which simplifies to
[[-1 if not (i and j and n+1-i and n+1-j) else m[i-1][j-1] for j in range(n+2)] for i in range(n+2)]
but it is probably simpler to use comparisons
[[m[i-1][j-1] if 1 < i < n and 1 < j < n else -1 for j in range(n+2)] for i in range(n+2)]
or with abs():
[[-1 if abs((n+1)/2 - i) == (n+1)/2 or abs((n+1)/2-j) == (n+1)/2 else m[i-1][j-1] for j in range(n+2)] for i in range(n+2)]
which works by setting the element to -1 if the distance to the center of the matrix is equal to half the width of the matrix.
I am not entirely sure whether you want to access the 'edge' elements once you created the expanded matrix or whether you want to simplify the expansion process itself, but your question addresses the first scenario, so I'll assume that one.
Letting the list have n lists of length m (nxm matrix),
(i%(n-1))*(j%(m-1))==0
should work, as the first and last row set the first factor to 0 and the first and last column set the second to 0.
Related
Let's say I've got a list of lists (or more conceptually accurate a 2D array):
list = [[1,1,0,0,0],
[1,1,2,0,0],
[0,2,2,2,0],
[0,0,0,2,0],
[0,0,0,1,0]]
I'd like to identify the different regions of identical values and rewrite the list so that each region has a unique value, like so:
list = [[1,1,2,2,2],
[1,1,3,2,2],
[0,3,3,3,2],
[0,0,0,3,2],
[0,0,0,4,2]]
I've mostly tried writing variations of a loop parsing the array per value and setting adjacent values equal to each other (which yea, is redundant I guess), BUT ensuring that island of 1s in the top left is distinct from the 1 in the bottom right was just not working. My attempts were spotty at best and non-functional at worst. Examples:
for x in list_length:
for y in sublist_length:
try:
if list[x][y] == list[x+1][y]:
list[x+1][y] = list[x][y]
except:
pass
or
predetermined_unique_value = 0
for x in list_length:
for y in sublist_length:
try:
if list[x][y] == list[x+1][y]:
list[x+1][y] = predetermined_unique_value
predetermined_unique_value += 1
except:
pass
and many slight variations on which directions (up, down, left, right from current spot/point) to check, brute forcing the loop by running it until all spots had been assigned a new value, etc.
Clearly I am missing something here. I suspect the answer is actually super simple, but I can't seem to find anything on google or reddit, or other answers here (I'm probably just conceptualizing it weirdly so searching for the wrong thing).
Just to reiterate, how could you parse that list of lists to organize values into adjacent regions based on identical data and rewrite it to ensure that those regions all have unique values? (I.E. so that there is only one region of the 0 value, one region of the 1 value, etc. etc.)
I hope this is enough information to help you help me, but in truth I just as much am not sure how to do this as I am doing it wrong. Please don't hesitate to ask for more.
Based on this answer you can do it with ndimage from the scipy library.
I applied your data to his answer and that's what I got as result:
from scipy import ndimage
import numpy as np
data_tup = ((1,1,0,0,0),
(1,1,2,0,0),
(0,2,2,2,0),
(0,0,0,2,0),
(0,0,0,1,0))
data_list = [[1,1,0,0,0],
[1,1,2,0,0],
[0,2,2,2,0],
[0,0,0,2,0],
[0,0,0,1,0]]
def find_clusters(array):
clustered = np.empty_like(array)
unique_vals = np.unique(array)
cluster_count = 0
for val in unique_vals:
labelling, label_count = ndimage.label(array == val)
for k in range(1, label_count + 1):
clustered[labelling == k] = cluster_count
cluster_count += 1
return clustered, cluster_count
clusters, cluster_count = find_clusters(data_list)
clusters_tup, cluster_count_tup = find_clusters(data_tup)
print(" With list of lists, Found {} clusters:".format(cluster_count))
print(clusters, '\n')
print(" With tuples of tuple, Found {} clusters:".format(cluster_count_tup))
print(clusters_tup)
Output:
With list of lists, Found 5 clusters:
[[2 2 0 0 0]
[2 2 4 0 0]
[1 4 4 4 0]
[1 1 1 4 0]
[1 1 1 3 0]]
With tuples of tuple, Found 5 clusters:
[[2 2 0 0 0]
[2 2 4 0 0]
[1 4 4 4 0]
[1 1 1 4 0]
[1 1 1 3 0]]
Both times the Output is a list of list. If you wish to have it different, the function needs to be changed inside.
You can use skimage.measure.label:
>>> import numpy as np
>>> from skimage import measure
>>>
>>> a = np.array([[1,1,0,0,0],
[1,1,2,0,0],
[0,2,2,2,0],
[0,0,0,2,0],
[0,0,0,1,0]])
>>> measure.label(a, background=a.max()+1)
array([[1, 1, 2, 2, 2],
[1, 1, 3, 2, 2],
[4, 3, 3, 3, 2],
[4, 4, 4, 3, 2],
[4, 4, 4, 5, 2]])
Note that the label function has an argument connectivity which determines how blobs/clusters are identified. The default for a 2D array is to consider diagonal neighbors. If that is undesired, connectivity=1 will consider only horizontal/vertical neighbors.
I'm not sure how good the performance of this solution is but here's a recursive approach to identify a connected segment. It will take a coordinate and return the same list of islands with every coordinate that was part of the same island as the given coordinate with True.
islands = [[1,1,0,0,0],
[1,1,2,0,0],
[0,2,2,2,0],
[0,0,0,2,0],
[0,0,0,0,0]]
def print_islands():
for row in islands:
print(row)
def get_bool_map(i, j):
checked_indexes = [[False] * len(islands[0]) ] * len(islands)
checked_cords = []
def check_island_indexes(island_value, m, i, j):
if i < 0 or j < 0:
return
try:
if m[i][j] != island_value:
return
else:
if [i, j] in checked_cords:
return
else:
checked_cords.append([i, j])
m[i][j] = True
except IndexError:
return
check_island_indexes(island_value, m, i - 1, j)
check_island_indexes(island_value, m, i + 1, j)
check_island_indexes(island_value, m, i, j - 1)
check_island_indexes(island_value, m, i, j + 1)
check_island_indexes(islands[i][j], islands, i, j)
get_bool_map(0, 4)
print_islands()
[1, 1, True, True, True]
[1, 1, 2, True, True]
[0, 2, 2, 2, True]
[0, 0, 0, 2, True]
[0, 0, 0, 1, True]
I want to generate a lexicographic series of numbers such that for each number the sum of digits is a given constant. It is somewhat similar to 'subset sum problem'. For example if I wish to generate 4-digit numbers with sum = 3 then I have a series like:
[3 0 0 0]
[2 1 0 0]
[2 0 1 0]
[2 0 0 1]
[1 2 0 0] ... and so on.
I was able to do it successfully in Python with the following code:
import numpy as np
M = 4 # No. of digits
N = 3 # Target sum
a = np.zeros((1,M), int)
b = np.zeros((1,M), int)
a[0][0] = N
jj = 0
while a[jj][M-1] != N:
ii = M-2
while a[jj][ii] == 0:
ii = ii-1
kk = ii
if kk > 0:
b[0][0:kk-1] = a[jj][0:kk-1]
b[0][kk] = a[jj][kk]-1
b[0][kk+1] = N - sum(b[0][0:kk+1])
b[0][kk+2:] = 0
a = np.concatenate((a,b), axis=0)
jj += 1
for ii in range(0,len(a)):
print a[ii]
print len(a)
I don't think it is a very efficient way (as I am a Python newbie). It works fine for small values of M and N (<10) but really slow beyond that. I wish to use it for M ~ 100 and N ~ 6. How can I make my code more efficient or is there a better way to code it?
Very effective algorithm adapted from Jorg Arndt book "Matters Computational"
(Chapter 7.2 Co-lexicographic order for compositions into exactly k parts)
n = 4
k = 3
x = [0] * n
x[0] = k
while True:
print(x)
v = x[-1]
if (k==v ):
break
x[-1] = 0
j = -2
while (0==x[j]):
j -= 1
x[j] -= 1
x[j+1] = 1 + v
[3, 0, 0, 0]
[2, 1, 0, 0]
[2, 0, 1, 0]
[2, 0, 0, 1]
[1, 2, 0, 0]
[1, 1, 1, 0]
[1, 1, 0, 1]
[1, 0, 2, 0]
[1, 0, 1, 1]
[1, 0, 0, 2]
[0, 3, 0, 0]
[0, 2, 1, 0]
[0, 2, 0, 1]
[0, 1, 2, 0]
[0, 1, 1, 1]
[0, 1, 0, 2]
[0, 0, 3, 0]
[0, 0, 2, 1]
[0, 0, 1, 2]
[0, 0, 0, 3]
Number of compositions and time on seconds for plain Python (perhaps numpy arrays are faster) for n=100, and k = 2,3,4,5 (2.8 ghz Cel-1840)
2 5050 0.040000200271606445
3 171700 0.9900014400482178
4 4421275 20.02204465866089
5 91962520 372.03577995300293
I expect time 2 hours for 100/6 generation
Same with numpy arrays (x = np.zeros((n,), dtype=int)) gives worse results - but perhaps because I don't know how to use them properly
2 5050 0.07999992370605469
3 171700 2.390003204345703
4 4421275 54.74532389640808
Native code (this is Delphi, C/C++ compilers might optimize better) generates 100/6 in 21 seconds
3 171700 0.012
4 4421275 0.125
5 91962520 1.544
6 1609344100 20.748
Cannot go sleep until all measurements aren't done :)
MSVS VC++: 18 seconds! (O2 optimization)
5 91962520 1.466
6 1609344100 18.283
So 100 millions variants per second.
A lot of time is wasted for checking of empty cells (because fill ratio is small). Speed described by Arndt is reached on higher k/n ratios and is about 300-500 millions variants per second:
n=25, k=15 25140840660 60.981 400 millions per second
My recommendations:
Rewrite it as a generator utilizing yield, rather than a loop that concatenates a global variable on each iteration.
Keep a running sum instead of calculating the sum of some subset of the array representation of the number.
Operate on a single instance of your working number representation instead of splicing a copy of it to a temporary variable on each iteration.
Note no particular order is implied.
I have a better solution using itertools as follows,
from itertools import product
n = 4 #number of elements
s = 3 #sum of elements
r = []
for x in range(n):
r.append(x)
result = [p for p in product(r, repeat=n) if sum(p) == s]
print(len(result))
print(result)
I am saying this is better because it took 0.1 secs on my system, while your code with numpy took 0.2 secs.
But as far as n=100 and s=6, this code takes time to go through all the combinations, I think it will take days to compute the results.
I found a solution using itertools as well (Source: https://bugs.python.org/msg144273). Code follows:
import itertools
import operator
def combinations_with_replacement(iterable, r):
# combinations_with_replacement('ABC', 2) --> AA AB AC BB BC CC
pool = tuple(iterable)
n = len(pool)
if not n and r:
return
indices = [0] * r
yield tuple(pool[i] for i in indices)
while True:
for i in reversed(range(r)):
if indices[i] != n - 1:
break
else:
return
indices[i:] = [indices[i] + 1] * (r - i)
yield tuple(pool[i] for i in indices)
int_part = lambda n, k: (tuple(map(c.count, range(k))) for c in combinations_with_replacement(range(k), n))
for item in int_part(3,4): print(item)
I am running a selection sort function in Python that works with numpy arrays instead of lists (so I can't use .pop for this, I don't think).
The function is:
def selectionSort(arr):
newArr = []
for i in range(len(arr)):
smallest = findSmallest(arr)
newArr.append((smallest))
arr = arr[(arr > smallest)]
return newArr
I want that "arr = arr[(arr > smallest)] which obviously doesn't work, to remove the smallest value (or, the value appended to newArr i.e the same value) from the passed array in the same way that .pop would do with a list.
I've tried things along these lines:
a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])
index = [2, 3, 6]
new_a = np.delete(a, index)
But couldn't get it to work. At the end of the day, I need to get something in the format of:
arr = randint(0,10,20)
to return an array sorted in ascending order. All I can manage is returning the smallest values repeated.
Thanks for any help
Try
arr = arr[np.where(arr > smallest)]
You may try:
arr = arr[ arr != np.min(a)]
This way you'll take from arr all the elements except the smallest one and reassign them to arr.
Your algorithm is almost correct. Indeed, it works if there are no duplicate values in arr:
import numpy as np
def selectionSort(arr):
newArr = []
for i in range(len(arr)):
smallest = findSmallest(arr)
newArr.append((smallest))
arr = arr[(arr > smallest)]
return newArr
findSmallest = np.min
# no duplicate values
auniq = np.random.choice(np.arange(20), (10,), replace=False)
print(auniq)
print(selectionSort(auniq))
Sample run:
[ 0 1 7 4 10 14 13 16 9 12]
[0, 1, 4, 7, 9, 10, 12, 13, 14, 16]
If there are duplicates it will crash because upon removing a minimum with duplicates the duplicates will be removed as well and that throws off the logic of the loop.
# duplicate values
adupl = np.random.randint(0, 9, (10,))
print(adupl)
# next line would crash
#print(selectionSort(adupl))
One fix is to only remove one copy of duplicates. This can for example be done using argmin which returns the index of the/one minimum, not its value.
def selectionSort2(arr):
arr = np.array(arr)
sorted = np.empty_like(arr)
for i in range(len(sorted)):
j = arr.argmin()
sorted[i] = arr[j]
arr = np.delete(arr, j)
return sorted
print(selectionSort2(adupl))
This works but is terribly inefficient because np.delete is more or less O(n). It is cheaper to swap the minimum element with a boundary element and then cut that off:
def selectionSort3(arr):
arr = np.array(arr)
sorted = np.empty_like(arr)
for i in range(len(sorted)):
j = arr[i:].argmin()
sorted[i] = arr[i + j]
arr[i], arr[i + j] = arr[i + j], arr[i]
return sorted
print(selectionSort3(adupl))
Looking at selectionSort3 we can observe that the separate output sorted is not actually needed, because arr has been sorted inplace already:
def selectionSort4(arr):
arr = np.array(arr)
for i in range(len(arr)):
j = arr[i:].argmin()
arr[i], arr[i + j] = arr[i + j], arr[i]
return arr
print(selectionSort4(adupl))
Sample output (adupl and output of selectionSort2-4):
[0 4 3 8 8 4 5 0 4 2]
[0 0 2 3 4 4 4 5 8 8]
[0 0 2 3 4 4 4 5 8 8]
[0 0 2 3 4 4 4 5 8 8]
sum_of_n takes an integer n and returns a List of length abs(n) + 1.
The List/Array contains the numbers in the arithmetic series produced by taking the sum of the consecutive integer numbers from 0 to n inclusive.
Example
5 -> [0, 1, 3, 6, 10, 15]
-5 -> [0, -1, -3, -6, -10, -15]
7 -> [0, 1, 3, 6, 10, 15, 21, 28]
def sum_n(n):
a=n+1
x=0
b=0
list1=[]
for x in range(0,a):
b=(x*(x+1)*0.5)
list1.append(int(b))
return list1
print sum_n(5)
print sum_n(-5)
----output------
[0, 1, 3, 6, 10, 15]
[]
please explain me how can I return list with negative integer??
For negative integers, you need to use a negative step in your range(). So:
if a < 0:
step = -1
else:
step = 1
for x in range(0, a, step):
Now, in your calculation of b, you're adding 1 to x. This also needs to be changed to -1 when doing negative numbers. So you can just throw step in where you had 1.
Also, there's a difference between multiplying by 0.5 and dividing by 2 when dealing with negative numbers, and to get the result you're looking for you want the latter. So your calculation of b should now be:
b = x * (x + step) // 2
As a bonus, this will always be an integer, so you don't need the int(b) later (though it won't hurt).
I think it's not an issue with the return, but that your list is actually empty. Did you mean to take the absolute value of n before assigning it to a?
You could add a print statement in your loop to see what it's doing.
#if a < 0:
a = -5 #just defined the variable for easy explanation
y = 0
list1 = [0]
for x in range (1,abs(a)+1):
for h in range(x+1):
y -= h #<---- here
list1.append(y)
y = 0
print (list1)
Output
>>>
[0, -1, -3, -6, -10, -15]
>>>
Just minest instead of sum.
I tried to solve a problem of map (matrix 4x4) using python.
I want to find Maximum number of elements in the path of a map provided the next node must be lesser than the previous node with all possible combinations of elements in the matrix.
4 8 7 3
2 5 9 3
6 3 2 5
4 4 1 6
The movement is like from an element can move to east-west-north-south
For example from m[0][1] can move to m[0][2] and m[1][1] 4-> 8 or 2
Here is the sample code but i have no idea to how to recursively check every element.
#import itertools
n = 4
matrix = [[4, 8, 7, 3 ], [2, 5, 9, 3 ], [6, 3, 2, 5 ], [4, 4, 1, 6]]
for index,ele in enumerate(matrix):
vals=[]
for i2,e2 in enumerate(ele):
for index2,ele2 in enumerate(ele):
if index < (n-1):
if ele2 > matrix[index+1] [index2]:
vals.append(matrix[index+1] [index2])
if index > 0:
if ele2 > matrix[index-1] [index2]:
vals.append(matrix[index-1] [index2])
if index2 < n-1:
if ele2 > matrix[index] [index2+1]:
vals.append(matrix[index] [index2+1])
if index2 >0:
if ele2 > matrix[index] [index2-1]:
vals.append(matrix[index] [index2-1])
how to recurse this function to loop till the end
For Example the answer will be like 8-5-3-2-1 (Longest Path with decreasing factor)
Try this recursion: The longest path starting at element (x, y) is the longest longest path starting at any of its strictly smaller neighbors, plus 1.
def longest_path(matrix):
def inner_longest_path(x, y):
best, best_path = 0, []
# for all possible neighbor cells...
for dx, dy in ((+1, 0), (-1, 0), (0, +1), (0, -1)):
# if cell is valid and strictly smaller...
if (0 <= x + dx < len(matrix) and 0 <= y + dy < len(matrix[x])
and matrix[x+dx][y+dy] < matrix[x][y]):
n, path = inner_longest_path(x+dx, y+dy)
# check if the path starting at that cell is better
if n > best:
best, best_path = n, path
return best + 1, [matrix[x][y]] + best_path
return max(inner_longest_path(x, y) for x, row in enumerate(matrix)
for y, _ in enumerate(row))
Note that this will do a lot of duplicate calculations. Adding memoization is left as an excercise to the reader.
Example:
>>> longest_path(matrix)
(5, [9, 5, 3, 2, 1])