问题
I have a serie of lines and want to extract some of them. This is the number of lines:
line_no= np.arange (17, 34)
These lines are arranged in two perependicular direction. I have shown them with bluw and red lines in the fig. I know where the direction is changing, it is called sep:
sep=25 # lines from 17 to 25 are blue and from 26 to end are red
Then, I have the number of the points that create the lines. I call them chunks, because each number can be chunk:
chunk_val=np.array([1,2,3,3,4])
This chunk_val
says how lines are created. I need to extract specific line numbers which are highlighted by a blue circle in the fig. For the red lines the algorithm is simpler. chunk_val[0]
is 1
, it means I have no red line there. chunk_val[1]
is 2
, so I have one line and I want that line (26
) because the previous chunk gave me no line. chunk_val[2]
is 3
, so I have two lines here and I want the one last line (28
out of 27
and 28
), because previous chunk gave me one line. chunk_val[3]
is 3
, there are again two line but I want none of them because the number of created red lines in this chunk is equal to previous chunk. chunk_val[3]
is 4
, it creates three line and I want to export the number of last one (33
out of 31
, 32
and 33
) because it is creating one line more than previous chunk. If chunk_val[3]
was 5
, then I wanted to save the last two line.
For blue lines, that connect the chunks it is a little bit more complicated. chunk_val[0]
is 1
and chunk_val[1]
is 2
, it means there is one connecting line because first chunk_value
defines how many lines can be there. Meanwhile, I want that line (17
), because there is only one line. If there were more lines, I wanted to pick the last one. From chunk_val[1]
to chunk_val[2]
I have two lines and I want the last one (19
out of 18
and 19
). Then, chunk_val[2]
to chunk_val[3]
there are three line and I want the last one (22
out of 20
, 21
and 22
). From chunk_value[3]
to chunk_value[4]
again there are three line and I want the last one (25
out of 23
, 24
and 25
). There is one very important note on how to pick these connecting (blue) lines: I want to start picking them from the first chunk_val
untill where values of chunk_val
change. In my example until the last number of chunk_val
I see a change (chunk_val[-2]
is 3
while chunk_val[-1]
is 4
). If chunk_val[-1]
was also 3
, then I wanted to stop picking the blue lines after going from chunk_val[1]
to chunk_val[2]
(I mean I only wanted to have 17
and 19
). These are the idea of my algorithm but I have no idea to code it in python. In summary I want to have the following list of numbers:
[17, 26, 19, 28, 22, 25, 33]
In advance, I do appreciate any contribution.
回答1:
Upon reflection, there is a simpler solution to this problem (which can also be easily adapted for its twin problem):
import numpy as np
from scipy.ndimage.interpolation import shift
# Input data
line_no = np.arange (17, 34)
sep = 25 # lines from 17 to 25 are blue and from 26 to end are red
chunk_val = np.array([1,2,3,3,4])
# Blue candidates
blue_A = line_no[:np.where(line_no == sep)[0][0]+1]
# Red candidates
red_A = line_no[np.where(line_no == sep)[0][0]+1:]
# Select blue lines
blue_index = (chunk_val[:-1]).cumsum() - 1
blues = blue_A[blue_index]
blue_shift = (chunk_val[-1] - chunk_val)[:-1]
blues[blue_shift == 0] = 0 # set value of zero if no further jagged lines
# Select red lines
red_index = (chunk_val[1:] - 1).cumsum() - 1
reds = red_A[red_index]
red_shift = (chunk_val - shift(chunk_val, 1, cval=0))[1:] # increments between successive series of red lines
reds[red_shift == 0] = 0 # set value of zero if no increment
# Merge blue lines and red lines
result = np.ravel(np.column_stack((blues, reds)))
result = result[result != 0] # remove zeros
print(result)
Output:
[17 26 19 28 22 25 33]
回答2:
I agree with @sai's comment that this is probably best handled with some classes that represent the problem. Possibly a structure that represents the blue line to the right of the point and the red line up from the point. As I don't understand the problem I'm not sure what's best.
The code below works for the specific example in the question. I don't know whether it genuinely solves the question for different control lists or how to test it. Delete or comment out the two print statements when not required.
def specific_values( control, start = 0 ):
cumulative = start
blues = [] # List of lists of blues
reds = [] # List of list of reds
for i in control[ :-1 ]: # The last item in control doesn't generate blues.
temp=[]
for j in range( cumulative, cumulative + i ):
temp.append( j )
blues.append(temp)
cumulative += i
print( blues )
for ix, i in enumerate( control[ 1: ] ):
# The first item in the control doesn't generate reds.
# The index is used to check whether the length of the red is less than
# the corresponding blue
temp = []
for j in range( cumulative, cumulative+i-1 ):
temp.append( j )
while len(temp) < len( blues[ix] ):
temp.append( None ) # Pad the red with None to match the corresponding blue.
reds.append(temp)
cumulative += i-1
print( reds )
res = []
for b_arr, r_arr in zip( blues, reds ):
res.append( b_arr[ -1 ] ) # Append last item in blues sub array to result
res.append( r_arr[ -1 ] ) # Append last item in reds sub array to result
return [ x for x in res if not x is None ] # Filter out any Nones
control = [ 1, 2, 3, 3, 4 ]
specific_values( control, 17 )
There may be better ways to solve this but this represents the pattern I can see. What happens if a later control point is less than it's predecessor or if a control point is zero?
来源:https://stackoverflow.com/questions/65509793/how-to-write-an-algorithm-for-finding-specific-values-of-a-numpy-array-in-python