Циклический просмотр и обновление значений массива до тех пор, пока не будет выполнено условие, или пока не будет выполнено 100 циклов? - PullRequest
0 голосов
/ 09 марта 2019

Работа в Python 3.7 на ноутбуке Jupyter.Я работаю над проектом, который будет циклически проходить через 2D Numpy Array («доска», если хотите) для проверки всех экземпляров числа 1. Когда он находит число 1, мне нужно проверить значения слева.Справа, над ним и под ним.Если какое-либо из значений рядом с ним равно 2, то сам этот элемент становится 2.

После циклического перемещения по всему массиву мне понадобится код, чтобы проверить, изменилась ли плата с самого началаэтой единственной петли.Если он не изменился, симуляция (цикл) должна закончиться.Однако, если он изменился, симуляция должна снова запуститься.Однако симуляция не должна повторяться более 100 витков.

Вот установка, ведущая к моей проблемной ячейке:

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
import numpy.random as rand
import time
from IPython.display import display, clear_output

def set_board(height=5,width=10,density=.75):
    city = np.zeros((height,width),dtype='int64')
    for i in range(height):
        for j in range(width):
            if rand.random() <= density:
                city[i,j] = 1
    return city

def VisMap(Map=set_board(),Colors=plt.cm.RdYlGn):
    MapVis = plt.imshow(Map, Colors)
    return MapVis

def onBoard(i, j, array):
    if (i >= 0 and i < array.shape[0]-1 
        and j >= 0 and j < array.shape[1]-1):
        return True
    return False

def getNeighborValues(i, j, board):
    neighborhood_indices = [(i-1,j),(i,j-1),(i+1,j),(i,j+1)]
    neighborhood_values = []
    for index in neighborhood_indices:
        if onBoard(index[0],index[1],board) == True:
            neighborhood_values.append(board[index[0],index[1]])
        pass
    return neighborhood_values

def startRumor(board):
    height, width = board.shape 
    height_quarters = int(height/4)
    width_quarters = int(width/4)
    starting_middle_height_index = height_quarters
    ending_middle_height_index = 3*height_quarters
    starting_middle_width_index = width_quarters
    ending_middle_width_index = 3*width_quarters
    found_starting_point = False 
    if np.all(board[starting_middle_height_index:ending_middle_height_index, starting_middle_width_index:ending_middle_width_index] == 0):
        i = rand.randint(starting_middle_height_index, ending_middle_height_index)
        j = rand.randint(starting_middle_width_index, ending_middle_width_index)
        board[i,j] = 2
        found_starting_point = True
    while not found_starting_point:
        i = rand.randint(starting_middle_height_index, ending_middle_height_index)
        j = rand.randint(starting_middle_width_index, ending_middle_width_index)
        if board[i,j] == 1:
            found_starting_point = True
            board[i, j] = 2

А вот ячейка, в которой я нахожусьвозникла проблема с (в частности, начиная с шага 5):

#Step 1: Initializing my board
StartingBoard = set_board(100,200,.4)

#Step 2: Visualizing my board
PreRumorVis = VisMap(StartingBoard)

#Step 3: Starting the rumor
startRumor(StartingBoard)

#Step 4: Visualizing the board after the rumor has started
PostRumorVis = VisMap(StartingBoard)

#Step 5: Create a copy of the city, and turn anything 
#with a 2 around it into a 2, and keep doing that for 100 
#loops. Or, if the city at the end of the loop is equal to 
#the one from the beginning of the loop, break it. If there 
#is some change, though, set the new city to now be the 
#updated copy, and loop through again. (In this case, it 
#probably should loop all 100 times).

City_Copy = StartingBoard.copy()
New_City = City_Copy.copy()
iterations = 0
for num in range(100):
    for i in range(City_Copy.shape[0]):
        for j in range(City_Copy.shape[1]):
            if City_Copy[i,j] == 1:
                if 2 in getNeighborValues(i,j, City_Copy):
                    New_City[i,j] = 2
                else:
                    New_City[i,j] = 1
    if np.array_equal(New_City, City_Copy) == True:
        break
    else:
        City_Copy = New_City.copy()
        iterations += 1

print("This rumor has been around for", iterations, "days.")            
New_City

Редактировать: я обнаружил, что сначала мне не хватало функции копирования, благодаря одному из комментариев.Тем не менее, я все еще получаю около 18 дней, когда оно должно быть 100 (или очень близко).Интересно, должен ли я открывать цикл for или цикл while?Проблема может быть где-то с установкой переменных, равных копиям ... Это меня немного смущает.Все это логично, но где-то есть болт.

1 Ответ

1 голос
/ 09 марта 2019

В Python операторы Assignment не копируют объекты, а создают привязки между целью и объектом . Когда мы используем = оператор, пользователь думает, что это создает новый объект, ну, это не так. Он только создает новую переменную, которая разделяет ссылку на исходный объект.

Пример: -

>>> a=np.array([[0,1],[0,2]])
>>> b=a
>>> np.array_equal(b,a)
True
>>> b[0][1]=1
>>> b
array([[0, 1],
       [0, 2]])
>>> a
array([[0, 1],
       [0, 2]])
>>> np.array_equal(b,a)
True

Это происходит из-за факта мелкого копирования . Мелкое копирование ограничено только составными объектами, такими как списки. Чтобы избежать этого, используйте глубокое копирование.

>>> import copy
>>> a=np.array([[0,1],[0,2]])
>>> b=copy.deepcopy(a) 
>>> np.array_equal(b,a)
True
>>>b[0][0]=1
>>> np.array_equal(b,a)
False

Решение: -

Поскольку вы назначили New_City = City_Copy, какие бы изменения в New_City не были сделаны, это отражается в City_Copy. Таким образом, они оба равны, и цикл прерывается сам в первый раз. Поэтому цикл не увеличивается . Попробуйте решить проблему с помощью глубокой копии.

Справка: -

  1. Мелкая копия против Глубокой копия
...