Has anyone tried creating a dynamic list of variables. Variable names will be supplied via a csv file which will be loaded as part of setup. I'm having trouble with defining the variable names.
Working:
create-turtles 1 [
let attribute-name item 0 attributes
set var attribute-name
let ID "123". ; atribute-name is ID and it correctly defined by assigning value 123 to ID
let attribute-value item 0 data
run (word "set " attribute-name " " attribute-value) ;
]
Not working:
create-turtles 1 [
let attribute-name item 0 attributes
set var attribute-name
run (word "let " var " " 123) --> This resolved to "let ID 123 ". However it didn't do anything
let attribute-value item 0 data
run (word "set " attribute-name " " attribute-value) ; --> At this point still getting error that nothing named ID is defined.
Everything works if i define the variable name (ID) explicitly either as turtle variable or local variable.
NetLogo doesn't have a way of declaring variables dynamically at runtime, which is what it seems like you're trying to do. To just get things working, you'll need to declare your variables ahead of time, and it seems like you want to use turtles-own
variables. Your example isn't complete, so I filled in some details here:
turtles-own [ID Name Score]
to setup
clear-all
let attributes ["ID" "Name" "Score"]
let data [123 "Jeffrey" 100]
create-turtles 1 [
let attribute-name item 0 attributes
let attribute-value item 0 data
; the `run` of the `set` string now works, but we need to quote strings
let value-string ifelse-value is-string? attribute-value [(word "\"" attribute-value "\"")] [attribute-value]
let set-command (word "set " attribute-name " " value-string)
run set-command
]
show [(list ID Name Score)] of turtles
; outputs `observer: [[123 0 0]]`
end
And we can generalize this just a bit with the range
primitive for all attributes and data:
turtles-own [ID Name Score]
to setup
clear-all
let attributes ["ID" "Name" "Score"]
let data [123 "Jeffrey" 100]
create-turtles 1 [
foreach range (length attributes) [ i ->
let attribute-name item i attributes
let attribute-value item i data
; the `run` of the `set` string now works, but we need to quote strings
let value-string ifelse-value is-string? attribute-value [(word "\"" attribute-value "\"")] [attribute-value]
let set-command (word "set " attribute-name " " value-string)
run set-command
]
]
show [(list ID Name Score)] of turtles
; outputs `observer: [[123 "Jeffrey" 100]]`
end
But, given what you're describing, I feel like using the Table extension might be a better way. It works well with reading what are key/value pairs from lists, and those can be added dynamically at runtime. This way each turtle can have its own table of values to store and use. This also lets you maintain flexibility when working with unknown attributes; you can just access values by the keys. Here is one way to adapt your example:
extensions [table]
turtles-own [data-table]
to setup
clear-all
let attributes ["ID" "Name" "Score"]
let data [123 "Jeffrey" 100]
; this zips up our two lists into a list of lists so it's easier for Table to read them
; you could also use the FP extension `fp:zip` prim for this
let zipped map [ i ->
(list (item i attributes) (item i data))
] (range length attributes)
create-turtles 1 [
set data-table table:from-list zipped
]
show [data-table] of turtles
; outputs `observer: [{{table: [["ID" 123] ["Name" "Jeffrey"] ["Score" 100]]}}]`
end