I'm trying to break out of a nested foreach loop using 2 lists of sorted turtles.
But instead of just leaving the inner loop, netlogo breaks out of the whole procedure.
I have a code like the one below (this one is made up, but has exactly the same structure):
to do-something
let xturtles sort-by [ [a b] -> [birthday] of a > [birthday] of b ] turtles
;; construct an ordered set
foreach xturtles [ the-xturtle ->
ask the-xturtle [
let xage birthday
let yturtles sort-by [ [a b] -> [birthday] of a > [birthday] of b ] turtles with [birthday < xage]
;; construct a second ordered set
foreach yturtles [ the-yturtle ->
let breakout-condition? false
ask the-yturtle [
if (hidden? ) [
set breakout-condition? true
]
]
if breakout-condition? [ stop ]
]
]
]
end
However, when the stop condition is reached, netlogo breaks out of the whole procedure, instead of continuing with the outer loop (the xturtles loop)?
Is that the expected behavior? If so, what is a good practice in this case?
Thanks!
Felix
It looks even nesting the stop within an extra ask procedure in the same procedure doesn't help. However, if you need a quick fix I think you can replace the second foreach loop with a standalone procedure that contains the stop as a workaround. For example, this procedure follows a similar format to yours and the same problem comes up- as soon as stop is called the broader foreach is exited.
to nest-foreach-example
ca
crt 1
let xs [ 1 2 3 4 ]
let ys [ 1 2 3 4 ]
foreach xs [
x ->
foreach ys [
y ->
ask turtles [
if y > x [
stop
]
]
print word x y
]
]
end
This prints out 11.
However, if you make a custom procedure to take the place of your "y" foreach loop, it works (with or without the ask turtles):
to nest-foreach-example-turtles
ca
crt 1
let xs [ 1 2 3 4 ]
let ys [ 1 2 3 4 ]
foreach xs [
x ->
for-y x ys
]
end
to for-y [ x_ ys ]
foreach ys [
y ->
ask turtles [
if y > x_ [
stop
]
]
print word x_ y
]
end
Outputs:
11
21
22
31
32
33
41
42
43
44
Related
I have this issue where i need a new list with, all the unique elements from list a, but the issue is that the list have different lengths.
[ 1; 2; 4; 5 ] |> List.except [ 2; 3; 5 ] // [ 1; 4 ]
That is, the following should do what you want
let c = a |> List.except b
Update
As #rcoy pointed out, List.except returns distinct elements only, i.e.
[ 1; 1 ] |> List.except [] = [ 1 ] // true
To keep duplicates, a straightforward way is
let b = [ 2 ]
let toRemove x = not(List.contains x b)
[ 1; 1; 2 ] |> List.filter toRemove // [ 1; 1 ]
Depending on the size of the b list and equivalency function (structural vs. referential), i.e. the cost of traversing and comparing, changing the datastructures might be beneficial. E.g.
open System.Collections.Generic
let b = [ 2 ]
let toRemove = HashSet(b)
[ 1; 1; 2 ] |> List.filter (fun x -> not(toRemove.Contains(x))) // [ 1; 1 ]
which is similar to what List.except does internally.
This may be a beginner question, but after using the NetLogo Progamming Guide I'm unable to find a solution...
I am trying to iterate over a pair of lists and conditionally update the values based on a test condition.
This thread in a Netlogo Forum which gave me the hint to use the LIST primitives reporter but I still can't get the expected output.
Here is a simplified example which describes my problem.
Please note, that listA and listB are both filled with variables.
to test
let a1 1
let a2 5
let listA (list a1 a2)
let b1 6
let b2 3
let listB (list b1 b2)
(foreach (list listA) (list listb) [
[a b] -> ifelse a < b [set a "a"][set b "b"]])
show lista
show listb
end
;expected Output
;observer: [a 5]
;observer: [6 b]
Could someone give me a hint? What am I doing wrong?
Lists in NetLogo are immutable- you can't change the values quite like this approach. map might be more suitable for this:
to test2
let a1 1
let a2 5
let listA (list a1 a2)
let b1 6
let b2 3
let listB (list b1 b2)
show ( map [ [ a b ] ->
ifelse-value ( a < b ) [ "a" ] [ a ] ]
listA listB ;; pass the lists [ 1 5 ] and [ 6 3 ]
)
show ( map [ [ a b ] ->
ifelse-value ( a > b ) [ "b" ] [ b ] ]
listA listB ;; pass the lists [ 1 5 ] and [ 6 3 ]
)
end
Note that I think your expected output for lista should be ["a" 5] not ["a" 0]- is that correct?
If you'd like to do this with foreach to modify the original lists, I would create an index ( 0 to the length of the list ) to pass to replace-item:
to test3
let a1 1
let a2 5
let listA (list a1 a2)
let b1 6
let b2 3
let listB (list b1 b2)
let indexer ( range 0 length listA )
foreach indexer [ ind ->
let current_a item ind listA
let current_b item ind listB
ifelse current_a < current_b [
set listA replace-item ind listA "a"
] [
set listB replace-item ind listB "b"
]
]
print listA
print listB
end
Can I create a list with atoms as reference for them to later use it in my move method?
createLists(X) ->
List = [
listA = lists:seq(1, X),
listB = [],
listC = []
],
List.
Then I create like T = hello:createLists(10).
move(List, A, B) ->
...
How can I obtain A and B using atoms? I'm pretty new to Erlang so the answer might be obvious.
move is supposed to move top element of the from A to B but I struggle to pass A and B when I do like hello:move(List, ?, ?).
Regarding the code in your comment, #armedor:
1 move(List, a, b, c) ->
2 Source = proplists:get_value(a, List),
3 Dest = proplists:get_value(b, List),
4 Help = proplists:get_value(c, List),
5 Temp1 = [lists:nth(1,Source)],
6 NewDest = [lists:append(Dest,Temp1)],
7 NewSource = lists:subtract(Source,Temp1),
8 List1=[NewSource,NewDest,Help].
Say List is defined as [ {a, lists:seq(1, 3)}, {b, []}, {c, []} ].
Line 8 isn't going to be a proplist anymore, but just the sublists themselves. Instead, create List1 as [{a, NewSource}, {b, NewDest}, Help].
You also don't need to assign to List1 in line 8, since the function is returning - just make the new list itself the last line, which will be the return value.
And the lists:nth and lists:subtract you're doing can be combined as
[Temp1 | NewSource] = Source
If it has closures, can I assume that I can use many of strong functional style techniques on there?
Yes, Smalltalk has closures. The following code creates a closure that returns the sum of its two arguments:
sum := [ :a :b | a + b ].
Closures are objects that can be instantiated, passed around and manipulated. To evaluate a closure you send value, value:, value:value:, ...
sum value: 1 value: 2.
Closures are prominently used with collections to iterate, filter, map, ... all values of a collection:
aCollection select: [ :each | each isOdd ].
aCollection inject: 0 into: [ :each :result | each + result ].
Furthermore, they are used for control structures like loops:
[ iterator hasNext ]
whileTrue: [ iterator next ].
1 to: 10 do: [ :each | ... ].
Also conditionals are implemented using closures:
condition
ifTrue: [ do this ]
ifFalse: [ do that ]
Pharo has them:
all VMs have closure support required
for latest images
makeAdder := [ :x | [ :y | x + y ]].
add2 := makeAdder value: 2.
add2 value: 3.
Returns 5.
But notice that
makeCounter := [ :init | [ init := init + 1. init ]].
won't work (Cannot store into ->init …), like (for example) in CL:
CL-USER> ((lambda (init) (lambda () (incf init))) 0)
#<COMPILED-LEXICAL-CLOSURE #xC7A495E>
CL-USER> (funcall *)
1
CL-USER> (funcall **)
2
CL-USER> (funcall ***)
3
If I'm not mistaken, this used to work before the new closure compiler was introduced. I'm not sure why it doesn't work with the new compiler.
I have a function that will parse the results of a DataReader, and I don't know how many items are returned, so I want to use a while..do loop to iterate over the reader, and the outcome should be a list of a certain type.
(fun(reader) ->
[
while reader.Read() do
new CityType(Id=(reader.GetInt32 0), Name=(reader.GetString 1), StateName=(reader.GetString 2))
])
This is what I tried, but the warning I get is:
This expression should have type 'unit', but has type 'CityType'. Use 'ignore' to discard the result of the expression, or 'let'
to bind the result to a name.
So what is the best way to iterate over a DataReader and create a list?
you can use list comprehension:
[
while reader.Read() do
let d = new CityType(Id=(reader.GetInt32 0), Name=(reader.GetString 1), StateName=(reader.GetString 2))
yield d
]
Here is one more example:
/// The squares of the first 10 integers
let squaresOfOneToTen = [ for x in 0..10 -> x*x ]
or
let squaresOfOneToTen = [ for x in 0..10 do yield x*x ]
You can also do it for sequences and arrays:
seq {
for i=1 to 9 do
for j=1 to 9 do
yield (i,j,i*j)
}
[| for i=1 to 100 do yield i*i |]
you can also yield a sub sequence in a sequence(yield!), here is an example using Project Euler 31.
Just to provide some additional information that may explain what is going on here - there are two ways of creating lists in F# and in both cases, you're writing something in square braces [ ... ] (which may be a bit confusing at first!)
List literals are used when you have a few expressions (known number of explicitly written expressions) and want to create a list containing the results of evaluating these expressions. For example:
[ 1; 2; 3; ] // list of constant expressions
[ 1+1; 2+2; 3+3 ] // creates list [ 2; 4; 6 ]
List comprehensions are used when you have some code that does something and generates list of elements (by producing elements during the calculation). This is what Yin Zhu uses in his answer. Some examples are:
[ yield 1; ] // generates singleton list [ 1 ]
[ yield 1; yield 2; ] // generates list with two elements
[ for x in 1 .. 10 do // iterates loop 10 times
yield x * x ] // ... generates element during every iteration
Advanced features
You can also use yield! to generate multiple elements at once:
[ yield! [ 1; 2 ] // generates a list containing [ 1; 2; 3; 4 ]
yield! [ 3; 4 ] ]
This can be used for writing recursive functions, so you could rewrite your code using recursion instead of loop (this would be useful if you needed to keep some state, but as your code looks currently, while is perfectly fine!)
let rec loop reader =
[ if reader.Read() then
yield new CityType(Id=(reader.GetInt32 0), Name=(reader.GetString 1),
StateName=(reader.GetString 2))
yield! loop reader ]
This is a pattern that often appears in list comprehensions, so it is useful to know about it :-).