Я хотел бы суммировать одно числовое свойство (AT1) патчей, которые имеют один и тот же идентификатор и сохраняют значение для этого идентификатора (процедура simulation здесь ниже). Я начал с идеи перебирать патчи, чтобы найти те, которые имеют один и тот же идентификатор (на основе внешнего файла).
Смотрите ниже воспроизводимый код, который не работает, он печатает сумму для всех патчей один за другим, а не только для одного идентификатора, я пробовал несколько способов.
globals [
AT-data
ABC
area
]
patches-own [
ID
AT1
AT2
seed
sum_AT1
]
to setup
;; here I just create patches with different values that also appear in the list
ca
set ABC [ "A" "B" "C" "D" "E" "F" "G" "H" "I" ]
ask patches [ set seed random 10 set ID one-of ABC
ifelse (seed = 4)
[ set pcolor orange] [set pcolor white]
]
end
to load
reset-timer
; first, we load the database file
; We check to make sure the file exists first
ifelse ( file-exists? "AT_data.txt" )
[
; We are saving the data into a list, so it only needs to be loaded once.
set AT-data []
file-open "AT_data.txt"
while [ not file-at-end? ]
[
; file-read gives variables stored in a double list
; Each iteration we append the next three-tuple to the current list: ID AT1 AT2
set AT-data sentence AT-data (list (list file-read file-read file-read))
]
user-message "File loading complete!"
file-close
assign-data
stop
]
[ user-message "There is no AT_data.txt file in current directory!" ]
file-close-all
print timer
end
to assign-data
reset-timer
ask patches with [seed = 4] [
let i 1
while [i < length AT-data] [
let current-inner-list item i AT-data
ifelse (ID = item 0 current-inner-list)
[ set AT1 item 1 current-inner-list set AT2 item 2 current-inner-list
stop]
[ set i i + 1 ]
]
]
print timer
end
to simulation
reset-timer
ask patches [
let i 1
while [i < length AT-data] [
let current-inner-list item i AT-data
ifelse (ID = item 0 current-inner-list)
;; I tried with and without this following line
;[ask patches with [ID = item 0 current-inner-list] [
[ set area area + AT1
print area
print ID
stop
]
;]
;; this one is an alternative
;[ print sum [AT1] of patches with [ID = item 0 current-inner-list]
;print ID
;]
[ set i i + 1 ]
]
]
print timer
end
AT_data.txt это
"A" 65 81
"B" 21 71
"C" 54 18
"D" 23 41
"E" 85 27
"F" 35 88
"G" 29 4
"H" 78 2
"I" 99 60
Спасибо за ваше время !





Мое первое замечание: у вас есть патчи, которые снова просят патчи в simulation.
Ваше второе решение было проще для работы. Главное здесь было вырвать его из контекста патча и позволить наблюдателю запустить его.
Для вывода на печать я предлагаю использовать такой формат, как print (word current-ID ": " current-sum). Это намного чище, когда вы хотите быстро проверить это после запуска модели.
to simulation-2
reset-timer
let i 0
while [i < length AT-data] [
let current-inner-list item i AT-data
let current-ID item 0 current-inner-list
let current-sum sum [AT1] of patches with [ID = current-ID]
print (word current-ID ": " current-sum)
set i i + 1
]
print timer
end
Для вашего первого решения ваша проблема заключалась в том, что у вас была только одна переменная области, которую вы увеличили. В следующем примере я превратил область в список той же длины, что и AT-данные, содержащий списки. Каждый внутренний список состоит из идентификатора и счетчика, установленного на 0 [["A" 0] ["B" 0] ... ["I" 0]].
Для этого я использую процедуру map. map берет каждый отдельный элемент списка, выполняет с ним определенную операцию и возвращает их все как новый список. В общем, это очень полезная процедура для изучения, когда вы будете работать со списками.
Затем я перебираю все исправления, как вы, и увеличиваю счетчик моего списка областей для правильного идентификатора. У меня есть две разные версии этого увеличения. Первый имеет множество локальных переменных, чтобы наглядно показать, как он работает. Вы выкапываете правильный подсписок, затем выкапываете правильную переменную, увеличиваете эту переменную, заменяете ее в подсписке и заменяете подсписок в основном списке. Второй делает то же самое, но в одной строке кода.
to simulation-1
reset-timer
set area map [inner-list -> list item 0 inner-list 0] AT-data ;creates a new list of lists of the form [["A" 0] ["B" 0] ... ].
ask patches [
let i 0
while [i < length AT-data] [
let current-inner-list item i AT-data
ifelse (ID = item 0 current-inner-list)
[ let inner-area-list item i area ;grab the correct innerlist
let increased-count item 1 inner-area-list + AT1 ;increment the second part of this inner list
set inner-area-list replace-item 1 inner-area-list increased-count ;put the incremented count back into the inner list
set area replace-item i area inner-area-list ;put the inner list back into the complete list
;; all these can be combined into a single line of code but that is more prone to errors
;set area replace-item i area (replace-item 1 item i area (item 1 item i area + AT1))
stop
]
[ set i i + 1 ]
]
]
print area
print timer
end
Только после создания всей этой вложенной структуры списка я подумал о том, что вы можете сделать это с обычным списком, в котором у вас есть только разные счетчики, а не идентификаторы, но эта структура делает его очень компактным, понятным и удобным для использования. для последующей обработки.
На самом деле я рассматриваю второй вариант, потому что мне нужно работать с несколькими свойствами патчей, принадлежащих одному и тому же идентификатору (суммируя одно свойство, выполняя некоторые математические операции с другим свойством с данными, поступающими из файла, а затем суммируя их). Поэтому я считаю, что лучше всего хранить эти результаты в списках. Однако я проверил команду map, но не смог создать новый список с более чем одним новым элементом, например ["A" 0 0] [ "B" 0 0 ] ... Если мне нравится set area map [inner-list -> list item 0 inner-list 0 inner-list 0] AT-data, возникает ошибка
или если я попробую, как set area1 map [inner-list -> list item 0 inner-list 0 ] AT-data set area2 map [inner-list -> list item 0 item 1 inner-list 0 ] area1 , это не сработает. Спасибо за понимание, я все еще в процессе обучения.
@Sarahdata Рад помочь вам. Ошибка, вероятно, возникает из-за того, что list по умолчанию ожидает ровно 2 входа. Вы можете изменить количество входных данных, используя скобки. В отличие от многих других языков программирования, сам list также должен быть включен в эти скобки. set area1 map [inner-list -> (list item 0 inner-list 0 0) ] AT-data генерирует формат [["A" 0 0] [ "B" 0 0 ] ... ].
Спасибо ! Я пробовал команду, которую вы написали, но без скобок... Я не понял из словаря (список значение1 значение2 (список значение1...)) что по умолчанию было 2 значения и может быть больше с скобкой. Теперь я буду понимать словарь совсем по-другому/эффективнее!! :D
Когда вы говорите, что у меня есть патчи, запрашивающие патчи снова, вы имеете в виду эту строку кода:
[ask patches with [ID = item 0 current-inner-list] [первого решения? Я действительно понял это, и поэтому я попробовал и без него... Большое спасибо LeirsW за решение с командойsumи подсказку об использовании командыword!