Python 3.1- Grid Simulation Conceptual issue

主宰稳场 提交于 2019-12-23 02:45:24

问题


The goal is to treat a 1D array as a 2D grid. A second 1D array gives a list of values that need to be changed in the grid, and a third array indicates by how much.

The catch is that the values surrounding a modified value is changed also.

The example below stays as a 1D array, but makes calculations on it as if it was a 2D grid. It works; but currently it changes all values in the grid that match to a value in the 1D list (sample). I wan't to only convert 1 value and its surroundings, for 1 value in the list.

i.e. If the list is [2,3]; I only want to change the first 2 and 3 value that comes across in the iteration. The example at the moment, alters every 2 in the grid.

What is confusing me is that (probably because of the way I have structured the modifying calculations), I can't simply iterate through the grid and remove a list value each time it matches.

Thank you in advance for your time!!

The code is following;

import numpy

def grid_range(value):
    if value > 60000:
        value = 60000
        return (value)
    elif value < 100:
        value = 100
        return(value)
    elif value <= 60000 and value >= 100:
        return(value)


def grid(array,samples,details):

    original_length = len(array)
    c = int((original_length)**0.5)

    new_array = []                                                                  #create a new array with the modified values

    for elem in range (len(array)):                                                 #if the value is in samples
        if array[elem] in samples:
            value = array[elem] + (array[elem] * (details[1]/100))
            test_range = grid_range(value)
            new_array.append(test_range)

        elif ((elem + 1) < original_length) and array[elem - 1] in samples:                                          #change the one before the value                                 
            if (len(new_array) % c == 0) and array[elem + 1] not in samples:                             
                new_array.append(array[elem])
            else:
                new_forward_element = array[elem] +(array[elem] * (details[2]/100))   
                test_range1 = grid_range(new_forward_element)
                new_array.append(test_range1)

        elif ((elem + 1) < original_length) and (array[elem + 1]) in samples:       #change the one before and that it doesn't attempt to modify passed the end of the array                                 
            if (len(new_array) + 1) % c == 0:
                new_array.append(array[elem])
            else:
                new_back_element = array[elem] +(array[elem] * (details[2]/100))
                test_range2 = grid_range(new_back_element)    
                new_array.append(test_range2)

        elif ((elem+c) <= (original_length - c))and(array[elem + c]) in samples:    #if based on the 9 numbers on the right of the keyboard with test value numebr 5; this is position '2' 
            extra1 = array[elem] +(array[elem] * (details[2]/100))
            test_range3 = grid_range(extra1)
            new_array.append(test_range3)

        elif (array[abs(elem - c)]) in samples:                                     #position '8'
            extra2 = array[elem] +(array[elem] * (details[2]/100))
            test_range4 = grid_range(extra2)
            new_array.append(test_range4)

        elif (array[abs(elem - (c-1))]) in samples:                                 #position '7' 
            if (elem - (c-1)) % c == 0:
                new_array.append(array[elem])
            else:
                extra3 = array[elem] +(array[elem] * (details[2]/100))
                test_range5 = grid_range(extra3)
                new_array.append(test_range5)

        elif (array[abs(elem - (c+1))]) in samples:                                 #position '9'    
            if (elem - (c+1) + 1) % c == 0:
                new_array.append(array[elem])

            else:
                extra4 = array[elem] +(array[elem] * (details[2]/100))
                test_range6 = grid_range(extra4) 
                new_array.append(test_range6)

        elif ((elem +(c-1)) < original_length) and (array[elem + (c-1)]) in samples:    #position '1', also not passed total array length
            if (elem + (c-1)+ 1) % c == 0:
                new_array.append(array[elem])
            else:            
                extra5 = array[elem] +(array[elem] * (details[2]/100))
                test_range7 = grid_range(extra5)
                new_array.append(test_range7)

        elif (elem + (c+1)) < (len(array)- c) and (array[elem + (c+1)]) in samples:     #position '3', also not passed total array length
            if (elem + (c+1)) % c == 0:
                new_array.append(array[elem])
            else:
                extra6 = array[elem] +(array[elem] * (details[2]/100))
                test_range8 = grid_range(extra6)
                new_array.append(test_range8)

        else:
            new_array.append(array[elem])

    return(new_array)


a = [16,2,20,4,14,6,70,8,9,100,32,15,7,14,50,20,17,10,9,20,7,17,50,2,19,20]
samples = [2]
grid_details = [10,50,100]

result = grid(a,samples,grid_details)

EDIT:

Based on your answer Joe, I have created a version which modifies the main value (centre) by a specific % and the surrounding elements by another. However, how do I ensure that the changed values are not converted again during the next iteration of samples.

Thank you for your time!

Example code:

def grid(array,samples,details):

    #Sides of the square (will be using a squarable number
    Width = (len(array)) ** 0.5
    #Convert to grid
    Converted = array.reshape(Width,Width)
    #Conversion details
    Change = [details[1]] + [details[2]] 
    nrows, ncols = Converted.shape

    for value in samples:

        #First instance where indexing returns it
        i,j  = np.argwhere(Converted == value)[0]

        #Prevent indexing outside the boudaries of the
        #array which would cause a "wraparound" assignment
        istart, istop = max(i-1, 0), min(i+2, nrows)
        jstart, jstop = max(j-1, 0), min(j+2, ncols)


        #Set the value within a 3x3 window to their "new_value"  
        for elem in Converted[istart:istop, jstart:jstop]:

        Converted[elem] = elem + (elem * (value * ((Change[1]/100))

        #Set the main value to the new value  
        Converted[i,j] = value + (value * ((Change[0])/100))


    #Convert back to 1D list
    Converted.tolist()

    return (Converted)


a =  [16,2,20,4,14,6,70,8,9,100,32,15,7,14,50,20,17,10,9,20,7,17,50,2,19,20,21,22,23,24,25]
samples = [2, 7]
grid_details = [10,50,100]

result = grid(a,samples,grid_details)

print(result)

PS: I wan't to avoid modifying any value in the grid, which has previously been modified, be it the main value or the surrounding values.


回答1:


First off, I'm not quite sure what you're asking, so forgive me if I've completely misunderstood your question...

You say that you only want to modify the first item that equals a given value, and not all of them. If so, you're going to need to add a break after you find the first value, otherwise you'll continue looping and modify all the other values.

However, there are better ways to do what you want.

Also, you're importing numpy at top and then never(?) using it...

This is exactly the sort of thing that you'd want to use numpy for, so I'm going to give an example of using it.

It appears that you're just applying a function to a 3x3 moving window of a 2D array, where the values of the array match some given value.

If we want to set 3x3 area around a given index to some value, we'd just do something like this:

x[i-1:i+1, j-1:j+1] = value 

...where x is your array, i and j are the row and column, and value is the value you want to set them to. (similarly, x[i-1:i+1, j-1:j+1] returns the 3x3 array around <i,j>)

Furthermore, if we want to know the <i,j> indicates where a particular value occurs within an array, we can use numpy.argwhere which will return a list of the <i,j> indicates for each place where a given condition is true.

(Using conditionals on a numpy array results in a boolean array showing where the condition is true or false. So, x >= 10 will yield a boolean array of the same shape as x, not simply True or False. This lets you do nice things like x[x>100] = 10 to set all values in x that are above 100 to 10.)

To sum it all up, I believe this snippet does what you want to do:

import numpy as np

# First let's generate some data and set a few duplicate values
data = np.arange(100).reshape(10,10)
data[9,9] = 2
data[8,6] = 53

print 'Original Data:'
print data

# We want to replace the _first_ occurences of "samples" with the corresponding
# value in "grid_details" within a 3x3 window...
samples = [2, 53, 69]
grid_details = [200,500,100]

nrows, ncols = data.shape
for value, new_value in zip(samples, grid_details):
    # Notice that were're indexing the _first_ item than argwhere returns!
    i,j = np.argwhere(data == value)[0]

    # We need to make sure that we don't index outside the boundaries of the
    # array (which would cause a "wraparound" assignment)
    istart, istop = max(i-1, 0), min(i+2, nrows)
    jstart, jstop = max(j-1, 0), min(j+2, ncols)

    # Set the value within a 3x3 window to be "new_value"
    data[istart:istop, jstart:jstop] = new_value

print 'Modified Data:'
print data

This yields:

Original Data:
[[ 0  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 26 27 28 29]
 [30 31 32 33 34 35 36 37 38 39]
 [40 41 42 43 44 45 46 47 48 49]
 [50 51 52 53 54 55 56 57 58 59]
 [60 61 62 63 64 65 66 67 68 69]
 [70 71 72 73 74 75 76 77 78 79]
 [80 81 82 83 84 85 50 87 88 89]
 [90 91 92 93 94 95 96 97 98  2]]

Modified Data:
[[  0 200 200 200   4   5   6   7   8   9]
 [ 10 200 200 200  14  15  16  17  18  19]
 [ 20  21  22  23  24  25  26  27  28  29]
 [ 30  31  32  33  34  35  36  37  38  39]
 [ 40  41 500 500 500  45  46  47  48  49]
 [ 50  51 500 500 500  55  56  57 100 100]
 [ 60  61 500 500 500  65  66  67 100 100]
 [ 70  71  72  73  74  75  76  77 100 100]
 [ 80  81  82  83  84  85  50  87  88  89]
 [ 90  91  92  93  94  95  96  97  98   2]]

Finally, you mentioned that you wanted to "view something as both an N-dimensional array and a "flat" list". This is in a sense what numpy arrays already are.

For example:

import numpy as np

x = np.arange(9)
y = x.reshape(3,3)

print x
print y

y[2,2] = 10000

print x
print y

Here, y is a "view" into x. If we change an element of y we change the corresponding element of x and vice versa.

Similarly, if we have a 2D array (or 3D, 4D, etc) that we want to view as a "flat" 1D array, you can just call flat_array = y.ravel() where y is your 2D array.

Hope that helps, at any rate!




回答2:


You didn't specify that you had to do it any specific way so I'm assuming you're open to suggestions. A completely different(and IMHO simpler) way would be to make an array of arrays:

grid = [[0,0,0,0,0],
        [0,0,0,2,0],
        [1,0,0,0,0],
        [0,0,0,0,0],
        [0,0,3,0,0]]

To access a location on the grid, simply supply the index of the list(the row), then the index of the location on that grid(the column). For example:

1 = grid[2][0]
2 = grid[1][3]
3 = grid[4][2]

To create a non-hardcoded grid(e.g. of a variable size):

def gridder(width,height):
    list = []
    sublist = []
    for i in range(0,width):
        sublist.append(1)
    for i in range(0,height):
        list.append(sublist)
    return list

To modify a part of your grid:

def modifier(x,y,value):
    grid[y][x] = value

*If this is homework and you're supposed to do it the way the specified in your answer, then you probably can't use this answer.



来源:https://stackoverflow.com/questions/4870771/python-3-1-grid-simulation-conceptual-issue

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!