2016-03-13 2 views
0

Я пытаюсь случайным образом создать решетку 2D 20х20 с 1 и -1 в Python. Я генерирую 20 разных строк, и все, кажется, идет хорошо, пока я на самом деле не пытаюсь добавить сгенерированные строки в большой массив, A. Функция печати возвращает 20 различных произвольно сгенерированных строк точно так, как я хочу, но когда я добавляю функцию добавления, она добавляет только первую сгенерированную строку в массив двадцать раз.Создание случайной 2D-решетки: Python добавляет одну и ту же строку несколько раз вместо новой строки каждый раз

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

from random import randint 
# generating the lattice 
A = [] 
row = [0]*20 
def genrow(): 
    for i in range(0,20): 
     p = randint(1,100) 
     if p < 50: 
      row[i] = 1 
     else: 
      row[i] = -1 
    return row 

def newrow():     
    for j in range(0,20): 
     genrow() 
     print(row) 
     A.append(row) 

newrow() 

print(A) 
+1

Является ли ваш отступ неправильным только в сообщении или в коде, в котором вы работаете? 'if p <50' и что угодно до возврата должно быть отступом 8 пробелов ... – Ilja

+1

Вы говорите« первая сгенерированная строка », как если бы вы создали несколько строк, но я вижу только одну строку, в которой говорится« строка = ', а затем набор команд, которые изменяют эту единственную строку. Если вы уточните, в какой строке кода, который, по вашему мнению, создается новая строка, мы узнаем, какой вопрос следует закрыть, как дубликат. :-) – DSM

ответ

2

Это потому, что вы работаете с глобальным row, и списки изменяемы, поэтому вы добавляете ссылку на строку, но вы снова и снова меняете эту строку.

Возможным решением было бы скопировать строку перед добавлением:

from random import randint 
# generating the lattice 
A = [] 

def genrow(): 
    for i in range(0,20): 
     p = randint(1,100) 
     if p < 50: 
      row[i] = 1 
     else: 
      row[i] = -1 
    return row 

def newrow():     
    for j in range(0,20): 
     genrow() 
     #print(row) 
     A.append(row.copy()) # Copy it before appending. 

newrow() 

print(A) 

Альтернатива заключается в создании новых строк в вашей функции и добавить их:

from random import randint 
# generating the lattice 
A = [] 

def genrow():  
    row = [None] * 20 # Create a new row 
    for i in range(0,20): 
     row[i] = 1 if randint(1,100) < 50 else -1 # Notice I changed this to make it shorter 
    return row 

def newrow(): 
    for j in range(0,20): 
     row = genrow() # Catch the returned row 
     A.append(row) # Append the new row not as copy this time 

newrow() 
print(A) 

Вы можете даже сделать его короче еще со списком лиц:

from random import randint 
# generating the lattice 

def genrow():  
    return [1 if randint(1,100) < 50 else -1 for _ in range(20)] 

def newrow(): 
    return [genrow() for _ in range(20)] 

A = newrow() 
print(A) 

можно было бы даже объединить этот список c omprehensions в одном:

def newrow(): 
    return [[1 if randint(1,100) < 50 else -1 for _ in range(20)] for _ in range(20)] 

Обратите внимание, что все они делают то же самое с различными сложностями и подходами. Важным фактом является то, что вы либо copy, либо создаете новые списки, которые вы добавляете.Все остальное просто сокращает (и, вероятно, быстрее).

+1

плюс 1 для ознакомления с списком –

+0

ну, если вы ищете краткость вместо объяснения исходного кода, то numpy победит ... :) – Ilja

+0

Я думаю, что недоразумение было просто изменчивостью списков, какое еще объяснение должно быть там ? Я просто увидел возможность предоставить некоторые альтернативы (с использованием аргументов и возвратов) и некоторые дополнительные идеи (список понятий и однострочный '' if ... else ... '') и проиллюстрировать их в этом коде. Почему я не должен их предоставлять? – MSeifert

0

список является изменяемым объектом, поэтому если у вас есть row_1 = row, а затем row_2 = row, а затем, когда вы изменяете row_1, row_2 будет изменен, а также.

Вот что вы делаете (при условии, что отступы, как я догадался, в моем комментарии)

Вы имеете глобальную переменную строку, что вы изменили в вашей функции genrow() - изменить все время и перезаписывать старые результаты , Обратите внимание, что у вашей функции нет ввода, но , даже передавая эту переменную вашей функции, не помогло бы. Поскольку он остается одной переменной с множеством разных имен внутри и снаружи функции.

Вам нужно сгенерировать новую строку в вашей функции. Это все!

Для дальнейшего чтения, странно, this link я получил сегодня рекомендованные, это то, что вам нужно понять (ну, если вам нравится, вы необходимость только присвоить строку внутри genrow()).


Или, для краткости, это весь код, вам нужно:

import numpy as np 
A = 2 * np.random.randint(0, 2, (20, 20)) - 1 

, что это все ... разочаровывающими, не так ли? :)

+1

Не должно быть '' A = np.random.choice ([- 1, 1], (20, 20)) ''? – MSeifert

+0

О, вы правы, я недостаточно читал оригинальный код ... Я отредактирую – Ilja

+0

ahh, теперь я чувствую себя таким глупым. Все это было очень проницательно. Наверное, поэтому они предупредили меня о глобальных переменных ...! – cappuccino

0

Оба следующих фрагмента кода должны быть отступом в определении функции жанра.

row = [0]*20 

и

if p < 50: 
    row[i] = 1 
else: 
    row[i] = -1 
return row 

прямо сейчас единственный код, который вы выполняете 20x является

for i in range(0,20): 
     p = randint(1,100) 

строка только быть изменен один раз.

Смежные вопросы