Changing specific index's in list - python

Say I had a list:
lis = [0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0]
Would there be any way too take out the first 4 values of the list, make them :
[4, 2, 2, 4]
and the put them back in the list so the list now looks like
[4, 2, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
and do all of this without making the list
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
at the start.
Also if possible, can you make a loop to do this for all the 4 values available.
So that the list now looks like:
[4, 2, 2, 4, 4, 2, 2, 4, 4, 2, 2, 4, 4, 2, 2, 4]

lis = [0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0]
fill = [4, 2, 2, 4]
for i in range(0, len(lis), len(fill)):
lis[i : i + len(fill)] = fill
print(lis)
This outputs:
[4, 2, 2, 4, 4, 2, 2, 4, 4, 2, 2, 4, 4, 2, 2, 4]

Just do like this:
lis1 = [0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0]
# change first 4 index
lis1[:4] = 4,2,2,4
print(lis1)
# [4, 2, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
lis2 = [0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0]
# change every 4 index in loop
for i in range(0,len(lis2),4):
lis2[i:i+4] = 4,2,2,4
print(lis2)
# [4, 2, 2, 4, 4, 2, 2, 4, 4, 2, 2, 4, 4, 2, 2, 4]

Use itertools.cycle and itertools.islice:
from itertools import cycle, islice
lis = [0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0]
out = list(map(int, islice(cycle('4224'), len(lis))))
print(out)
# [4, 2, 2, 4, 4, 2, 2, 4, 4, 2, 2, 4, 4, 2, 2, 4]
Or a simpler way (without any imports):
lis = [0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0]
out = list(map(int, '4224' * (len(lis) // 4)))
print(out)
# [4, 2, 2, 4, 4, 2, 2, 4, 4, 2, 2, 4, 4, 2, 2, 4]

def list_function(original_list, list_of_value_to_subst):
original_list[:len(list_of_value_to_subst)]=list_of_value_to_subst
print (original_list)
subst_list = list(map(int, list_of_value_to_subst * (len(original_list) // len(list_of_value_to_subst))))
print (subst_list)
lis = [0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0]
list_of_value_to_subst=[4, 2, 2, 4]
list_function(lis, list_of_value_to_subst)
output:
[4, 2, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[4, 2, 2, 4, 4, 2, 2, 4, 4, 2, 2, 4, 4, 2, 2, 4]

Another solution, would be to do the following:
For your first question:
lis = [0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0]
ins = [4, 2, 2, 4]
lis[:len(ins)] = ins
print(lis)
Output:
[4, 2, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
For your second question:
lis = [0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0]
lis = ins * int(len(lis) / len(ins))
print(lis)
Output:
[4, 2, 2, 4, 4, 2, 2, 4, 4, 2, 2, 4, 4, 2, 2, 4]

Given the list of numbers you want to replace the first part of lis with:
replace_lis = [4, 2, 2, 4]
You can iterate over the length of replace_lis, and fill in the index spots in lis accordingly:
for i in range(len(replace_lis)):
if i < len(lis):
lis[i] = replace_lis[i]
The i < len(lis) is if replace_lis could be bigger than lis. If there is no chance of that, you can safely omit that if statement.

Here is your original list:
lis = [0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0]
and you'd like to replace the first 4 items with:
[4, 2, 2, 4]
Let's assign the new values a new variable. Let's call it update. So:
update = [4, 2, 2, 4]
Here is your code:
lis = [0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0]
update = [4, 2, 2, 4]
for i in range(0, len(update)):
lis[i] = update[i]
print(lis)

Related

Why does this adj_matrix keep writing to the same row instead of iterating over the rows?

I am trying to create an adjacency matrix from an adjacency dictionary.
Basically I want to create an empty matrix filled with zeros. Then iterate over every item in the adjacency dictionary and assign the correct weight in the matrix. But for some reason the code keeps assigning the values to the same row. I used matrix[][] to assign. Using python 3.7.
digraph = make_digraph() # A function that creates a class containing the adj_dict
adj_matrix = [[0] * len(digraph.adj_dict)] * len(digraph.adj_dict) # empty matrix
print(adj_matrix)
for source, destinations in digraph.adj_dict.items():
for destination in destinations:
print(int(source[1:]), int(destination[1:]), digraph.adj_dict[source][destination])
adj_matrix[int(source[1:])][int(destination[1:])] = digraph.adj_dict[source][destination]
print(adj_matrix)
But it gives output:
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
0 1 4
1 2 1
1 7 2
1 8 2
2 11 3
3 4 1
3 12 2
4 5 1
4 8 3
4 14 2
5 6 2
5 9 2
6 0 1
6 10 2
7 9 2
8 9 2
8 11 1
10 0 1
10 7 2
10 9 3
11 1 4
11 12 4
12 2 1
12 8 3
12 13 2
13 4 2
14 9 2
[[1, 4, 1, 0, 2, 1, 2, 2, 3, 2, 2, 1, 4, 2, 2], [1, 4, 1, 0, 2, 1, 2, 2, 3, 2, 2, 1, 4, 2, 2], [1, 4, 1, 0, 2, 1, 2, 2, 3, 2, 2, 1, 4, 2, 2], [1, 4, 1, 0, 2, 1, 2, 2, 3, 2, 2, 1, 4, 2, 2], [1, 4, 1, 0, 2, 1, 2, 2, 3, 2, 2, 1, 4, 2, 2], [1, 4, 1, 0, 2, 1, 2, 2, 3, 2, 2, 1, 4, 2, 2], [1, 4, 1, 0, 2, 1, 2, 2, 3, 2, 2, 1, 4, 2, 2], [1, 4, 1, 0, 2, 1, 2, 2, 3, 2, 2, 1, 4, 2, 2], [1, 4, 1, 0, 2, 1, 2, 2, 3, 2, 2, 1, 4, 2, 2], [1, 4, 1, 0, 2, 1, 2, 2, 3, 2, 2, 1, 4, 2, 2], [1, 4, 1, 0, 2, 1, 2, 2, 3, 2, 2, 1, 4, 2, 2], [1, 4, 1, 0, 2, 1, 2, 2, 3, 2, 2, 1, 4, 2, 2], [1, 4, 1, 0, 2, 1, 2, 2, 3, 2, 2, 1, 4, 2, 2], [1, 4, 1, 0, 2, 1, 2, 2, 3, 2, 2, 1, 4, 2, 2], [1, 4, 1, 0, 2, 1, 2, 2, 3, 2, 2, 1, 4, 2, 2]]
This does not make any sense to me. To be clear, for example the second iteration "1 2 1" I expected to write to adj_matrix[1][2] = 1. But it appears to write to adj_matrix[0][2] = 1?
I think this line is a problem
adj_matrix = [[0] * len(digraph.adj_dict)] * len(digraph.adj_dict)
You are copying the same list len(digraph.adj_dict) times and then every row in the matrix points to the list at the same location in memory, but each row in the matrix should not be the same. Changing it to list comprehension like this
adj_matrix = [[0] * len(digraph.adj_dict) for _ in range(len(digraph.adj_dict))]
should fix it if there are not other problems.

List gets changed when Scope gets changed

When I append List in a for loop it changes it value correctly
and when I print it outside for loop it's value gets changed
arr=[]
b=[1,2,3,4,5,6,7]
for i in range(0,len(b)):
b[i]=0
arr.append(b)
print(arr[i])
Here output is
[0, 2, 3, 4, 5, 6, 7]
[0, 0, 3, 4, 5, 6, 7]
[0, 0, 0, 4, 5, 6, 7]
[0, 0, 0, 0, 5, 6, 7]
[0, 0, 0, 0, 0, 6, 7]
[0, 0, 0, 0, 0, 0, 7]
[0, 0, 0, 0, 0, 0, 0]
And here
arr=[]
b=[1,2,3,4,5,6,7]
for i in range(0,len(b)):
b[i]=0
arr.append(b)
print(arr)
Output is
[[0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0]]
On each iteration, you are adding a reference to the same list b to your arr, which means that when you later set new values to zero, you are modifying all of the lists inside arr simultaneously. To avoid this, you can append a copy of b to arr instead by using list(b), i.e.:
arr = []
b = [1, 2, 3, 4, 5, 6, 7]
for i in range(len(b)):
b[i] = 0
arr.append(list(b))
print(arr)
This outputs:
[[0, 2, 3, 4, 5, 6, 7],
[0, 0, 3, 4, 5, 6, 7],
[0, 0, 0, 4, 5, 6, 7],
[0, 0, 0, 0, 5, 6, 7],
[0, 0, 0, 0, 0, 6, 7],
[0, 0, 0, 0, 0, 0, 7],
[0, 0, 0, 0, 0, 0, 0]]

Need a recursive function to get all permutations of an array where each element is itself plus 0 to n

Sorry for the wording of the title as I am unsure how to phrase the question.
I am trying to get all permutations of an array where each element could be it's value plus 0 to n ('wild' value)
e.g.
The array [0, 1, 0, 2, 1] with the wild value equal to 1 would have the permutations:
[1, 1, 0, 2, 1]
[0, 2, 0, 2, 1]
[0, 1, 1, 2, 1]
[0, 1, 0, 3, 1]
[0, 1, 0, 2, 2]
The array [1, 2, 0, 0] with the wild value equal to 2 would have the permutations:
[3, 2, 0, 0]
[2, 3, 0, 0]
[2, 2, 1, 0]
[2, 2, 0, 1]
[1, 4, 0, 0]
[2, 3, 0, 0]
[1, 3, 1, 0]
[1, 3, 0, 1]
[1, 2, 2, 0]
[2, 2, 1, 0]
[1, 3, 1, 0]
[1, 2, 1, 1]
... and so on...
This is the code I have tried, but it is not producing the desired results:
def generateAllMatrices(length, buckets, ind, wild):
if ind == length:
# possible_buckets.append(buckets.copy())
print(buckets)
return
if wild != 0:
for i in range(1, wild + 1):
buckets[ind] += 1
generateAllMatrices(length, buckets, 0, wild - 1)
buckets[ind] -= wild
generateAllMatrices(length, buckets, ind + 1, wild)
An example result produced from the above code is:
Original = [1, 0, 0, 2, 0, 1, 0, 0, 0, 1, 1, 0, 0]
Wild = 1
Permutations:
[2, 0, 0, 2, 0, 1, 0, 0, 0, 1, 1, 0, 0]
[1, 1, 0, 2, 0, 1, 0, 0, 0, 1, 1, 0, 0]
[1, 0, 1, 2, 0, 1, 0, 0, 0, 1, 1, 0, 0]
[1, 0, 0, 3, 0, 1, 0, 0, 0, 1, 1, 0, 0]
[1, 0, 0, 2, 1, 1, 0, 0, 0, 1, 1, 0, 0]
[1, 0, 0, 2, 0, 2, 0, 0, 0, 1, 1, 0, 0]
[1, 0, 0, 2, 0, 1, 1, 0, 0, 1, 1, 0, 0]
[1, 0, 0, 2, 0, 1, 0, 1, 0, 1, 1, 0, 0]
[1, 0, 0, 2, 0, 1, 0, 0, 1, 1, 1, 0, 0]
[1, 0, 0, 2, 0, 1, 0, 0, 0, 2, 1, 0, 0]
[1, 0, 0, 2, 0, 1, 0, 0, 0, 1, 2, 0, 0]
[1, 0, 0, 2, 0, 1, 0, 0, 0, 1, 1, 1, 0]
[1, 0, 0, 2, 0, 1, 0, 0, 0, 1, 1, 0, 1]
[1, 0, 0, 2, 0, 1, 0, 0, 0, 1, 1, 0, 0]
Are there any similar algorithms I could reference for this? Or what route should I take regarding developing something that will produce what I need.
Thanks!
You could do the following:
import itertools
def make_reps(l, wild):
for indices in itertools.product(range(len(l)), repeat=wild):
new_l = list(l)
for i in indices:
new_l[i] += 1
yield new_l
With your given examples:
In [12]: list(make_reps([0, 1, 0, 2, 1], 1))
Out[12]:
[[1, 1, 0, 2, 1],
[0, 2, 0, 2, 1],
[0, 1, 1, 2, 1],
[0, 1, 0, 3, 1],
[0, 1, 0, 2, 2]]
In [14]: list(make_reps([1, 2, 0, 0], 2))
Out[14]:
[[3, 2, 0, 0],
[2, 3, 0, 0],
[2, 2, 1, 0],
[2, 2, 0, 1],
[2, 3, 0, 0],
[1, 4, 0, 0],
[1, 3, 1, 0],
[1, 3, 0, 1],
[2, 2, 1, 0],
[1, 3, 1, 0],
[1, 2, 2, 0],
[1, 2, 1, 1],
[2, 2, 0, 1],
[1, 3, 0, 1],
[1, 2, 1, 1],
[1, 2, 0, 2]]

Why is this function returning all zeros

Folks this is driving me crazy.
I have the following functions defined below
I get the expected result from maskArray() when I pass it anchor='top' or anchor='left', but it returns and all zeros numpy array in case of 'bottom' and 'right'. I thought i got the slicing wrong, so i experimented with the statements mask[-y:,:] = somevalue outside the function and it works so I believe the syntax is right. Not sure what is going on here.
Here are examples of function calls results
In [5]: x = np.round(np.random.rand(10,10) * 10).astype(np.uint8)
In [6]: x
Out[6]:
array([[ 3, 2, 1, 10, 4, 7, 7, 9, 6, 5],
[ 1, 6, 3, 0, 9, 3, 7, 6, 0, 4],
[ 4, 2, 5, 3, 4, 7, 6, 2, 0, 3],
[ 1, 4, 10, 2, 8, 1, 9, 10, 4, 8],
[ 9, 8, 3, 5, 3, 0, 10, 5, 2, 3],
[ 1, 9, 8, 6, 1, 3, 7, 4, 9, 3],
[ 8, 8, 4, 6, 9, 1, 10, 6, 9, 7],
[ 6, 2, 4, 8, 2, 9, 2, 4, 7, 4],
[ 7, 9, 2, 6, 9, 2, 6, 8, 7, 8],
[ 4, 6, 3, 5, 7, 5, 3, 3, 5, 5]], dtype=uint8)
In [7]: maskArray(x,0.3333,'top')
Out[7]:
array([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=uint8)
In [8]: maskArray(x,0.3333,'left')
Out[8]:
array([[1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 0, 0, 0, 0, 0, 0, 0]], dtype=uint8)
In [9]: maskArray(x,0.3333,'bottom')
Out[9]:
array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=uint8)
Can any of you see something that I'm not seeing ?
My other questions is : is there a way to make the slicing statement generic for any dimension of np.array ? meaning instead of having an if statement for each expected array.ndim (i.e: [:x,:] and [:x,:,:] )
Cheers
import numpy as np
def getChannels(srx):
try:
if srx.ndim == 2:
return 0
elif srx.ndim == 3:
return srx.shape[2]
else:
return None
except TypeError:
print("srx is not a numpy.array")
def maskArray(dsx, fraction, anchor):
if anchor == 'top':
y = np.round(dsx.shape[0] * fraction).astype(np.uint8)
mask = np.zeros_like(dsx)
if getChannels(dsx) == 0:
mask[:y,:] = 1
return mask
elif getChannels(dsx) == 3:
mask[:y,:,:] = 1
return mask
else:
return None
elif anchor == 'bottom':
y = np.round(dsx.shape[0] * fraction).astype(np.uint8)
mask = np.zeros_like(dsx)
if getChannels(dsx) == 0:
mask[-y:,:] = 1
return mask
elif getChannels(dsx) == 3:
mask[-y:,:,:] = 1
return mask
else:
return None
elif anchor == 'left':
x = np.round(dsx.shape[1] * fraction).astype(np.uint8)
mask = np.zeros_like(dsx)
if getChannels(dsx) == 0:
mask[:,:x] = 1
return mask
elif getChannels(dsx) == 3:
mask[:,:x,:] = 1
return mask
else:
return None
elif anchor == 'right':
x = np.round(dsx.shape[1] * fraction).astype(np.uint8)
mask = np.zeros_like(dsx)
if getChannels(dsx) == 0:
mask[:,-x:] = 1
return mask
elif getChannels(dsx) == 3:
mask[:,-x:,:] = 1
return mask
else:
return None
When you ask for the negative of a type uint8 variable, the result overflows, because negative values don't exist for this type:
>>> -np.round(10 * 0.3333).astype('uint8')
253
Use a signed integer type and it will work as expected:
>>> -np.round(10 * 0.3333).astype('int')
-3

Label regions with unique combinations of values in two numpy arrays?

I have two labelled 2D numpy arrays a and b with identical shapes. I would like to re-label the array b by something similar to a GIS geometric union of the two arrays, such that cells with unique combination of values in array a and b are assigned new unique IDs:
I'm not concerned with the specific numbering of the regions in the output, so long as the values are all unique. I have attached sample arrays and desired outputs below: my real datasets are much larger, with both arrays having integer labels which range from "1" to "200000". So far I've experimented with concatenating the array IDs to form unique combinations of values, but ideally I would like to output a simple set of new IDs in the form of 1, 2, 3..., etc.
import numpy as np
import matplotlib.pyplot as plt
# Example labelled arrays a and b
input_a = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 0],
[0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 0],
[0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 0],
[0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 0],
[0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 0],
[0, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 0],
[0, 0, 3, 3, 3, 3, 2, 2, 2, 2, 0, 0],
[0, 0, 3, 3, 3, 3, 2, 2, 2, 2, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
input_b = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 1, 3, 3, 3, 3, 3, 0, 0],
[0, 0, 1, 1, 1, 3, 3, 3, 3, 3, 0, 0],
[0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 0, 0],
[0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 0, 0],
[0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 0, 0],
[0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
# Plot inputs
plt.imshow(input_a, cmap="spectral", interpolation='nearest')
plt.imshow(input_b, cmap="spectral", interpolation='nearest')
# Desired output, union of a and b
output = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 1, 2, 3, 3, 3, 3, 0, 0],
[0, 0, 1, 1, 1, 2, 3, 3, 3, 3, 0, 0],
[0, 0, 1, 1, 1, 4, 7, 7, 7, 7, 0, 0],
[0, 0, 5, 5, 5, 6, 7, 7, 7, 7, 0, 0],
[0, 0, 5, 5, 5, 6, 7, 7, 7, 7, 0, 0],
[0, 0, 5, 5, 5, 6, 7, 7, 7, 7, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
# Plot desired output
plt.imshow(output, cmap="spectral", interpolation='nearest')
If I understood the circumstances correctly, you are looking to have unique pairings from a and b. So, 1 from a and 1 from b would have one unique tag in the output; 1 from a and 3 from b would have another unique tag in the output. Also looking at the desired output in the question, it seems that there is an additional conditional situation here that if b is zero, the output is to be zero as well irrespective of the unique pairings.
The following implementation tries to solve all of that -
c = a*(b.max()+1) + b
c[b==0] = 0
_,idx = np.unique(c,return_inverse= True)
out = idx.reshape(b.shape)
Sample run -
In [21]: a
Out[21]:
array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 0],
[0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 0],
[0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 0],
[0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 0],
[0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 0],
[0, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 0],
[0, 0, 3, 3, 3, 3, 2, 2, 2, 2, 0, 0],
[0, 0, 3, 3, 3, 3, 2, 2, 2, 2, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
In [22]: b
Out[22]:
array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 1, 3, 3, 3, 3, 3, 0, 0],
[0, 0, 1, 1, 1, 3, 3, 3, 3, 3, 0, 0],
[0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 0, 0],
[0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 0, 0],
[0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 0, 0],
[0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
In [23]: out
Out[23]:
array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 1, 3, 5, 5, 5, 5, 0, 0],
[0, 0, 1, 1, 1, 3, 5, 5, 5, 5, 0, 0],
[0, 0, 1, 1, 1, 2, 4, 4, 4, 4, 0, 0],
[0, 0, 6, 6, 6, 7, 4, 4, 4, 4, 0, 0],
[0, 0, 6, 6, 6, 7, 4, 4, 4, 4, 0, 0],
[0, 0, 6, 6, 6, 7, 4, 4, 4, 4, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
Sample plot -
# Plot inputs
plt.figure()
plt.imshow(a, cmap="spectral", interpolation='nearest')
plt.figure()
plt.imshow(b, cmap="spectral", interpolation='nearest')
# Plot output
plt.figure()
plt.imshow(out, cmap="spectral", interpolation='nearest')
Here is a way to do it conceptually in terms of set union, but not to GIS geometric union, since that was mentioned after I answered.
Make a list of all possible unique 2-tuples of values with one from a and the other from b in that order. Map each tuple in that list to its index in it. Create the union array using that map.
For example say a and b are arrays each containing values in range(4) and assume for simplicity they have the same shape. Then:
v = range(4)
from itertools import permutations
p = list(permutations(v,2))
m = {}
for i,x in enumerate(p):
m[x] = i
union = np.empty_like(a)
for i,x in np.ndenumerate(a):
union[i] = m[(x,b[i])]
For demonstration, generating a and b with
np.random.randint(4, size=(3, 3))
produced:
a = array([[3, 0, 3],
[1, 3, 2],
[0, 0, 3]])
b = array([[1, 3, 1],
[0, 0, 1],
[2, 3, 0]])
m = {(0, 1): 0,
(0, 2): 1,
(0, 3): 2,
(1, 0): 3,
(1, 2): 4,
(1, 3): 5,
(2, 0): 6,
(2, 1): 7,
(2, 3): 8,
(3, 0): 9,
(3, 1): 10,
(3, 2): 11}
union = array([[10, 2, 10],
[ 3, 9, 7],
[ 1, 2, 9]])
In this case the property that a union should be bigger or equal to its composits is reflected in increased numerical values rather than increase in number of elements.
An issue with using itertools permutations is that the number of permutations could be much larger than needed. It would be much larger if the number of overlaps per area is much smaller than the number of areas.
The question uses Union but the picture shows an Intersection. Divakar's answer replicates the pictured Intersection, and is more elegant than my solution below, which produces the Union.
One could make a dictionary of only the actual overlaps, and then work from that. Flattening the input arrays first makes this easier for me to see, I'm not sure if that is feasible for you:
shp = numpy.shape(input_a)
a = input_a.flatten()
b = input_b.flatten()
s = set(((i,j) for i,j in zip(a,b))) # unique pairings
d = {p:i for i,p in enumerate(sorted(list(s))} # dict{pair:index}
output_c = numpy.array([d[i,j] for i,j in zip(a,b)]).reshape(shp)
array([[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 1, 1, 1, 1, 1, 5, 5, 5, 5, 5, 0],
[ 0, 1, 1, 1, 1, 1, 5, 5, 5, 5, 5, 0],
[ 0, 1, 2, 2, 2, 4, 7, 7, 7, 7, 5, 0],
[ 0, 1, 2, 2, 2, 4, 7, 7, 7, 7, 5, 0],
[ 0, 1, 2, 2, 2, 3, 6, 6, 6, 6, 5, 0],
[ 0, 8, 9, 9, 9, 10, 6, 6, 6, 6, 5, 0],
[ 0, 0, 9, 9, 9, 10, 6, 6, 6, 6, 0, 0],
[ 0, 0, 9, 9, 9, 10, 6, 6, 6, 6, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])

Categories

Resources