I've been looking at examples and documentation; and I cannot figure out why I'm getting the
loop requires an even number of forms in binding vector error.
I believe the problem is in the loop and initializing usage-indicies. I just cannot figure out what I'm doing wrong.
(def usage-vec-len 13)
(defn ret-usage-indicies
"Takes a billed water consumption amount, and returns a vector of the ranges."
[reading]
(let [usage-indicies [0 0 0 0 0 0 0 0 0 0 0 0 0] curr-idx (- usage-vec-len 1)]
(loop [curr-reading reading ui usage-indicies curr-idx]
.
.
.
(if (= remaining-reading 0)
ui
(recur remaining-reading (assoc ui curr-idx curr-reading) (dec curr-idx)))))))
A loop form should look just like a let form. You can add comma whitespace for clarity:
(loop [symbol1 init1, symbol2 init2, ...] body-of-expressions)
It looks like you might want
(loop [curr-reading reading, ui usage-indicies, curr-idx curr-idx] ...)
where curr-index is initialized (rebound) to curr-index from the let expression.
Better, you could move the initialization you having going on in your let form down to the loop form itself. It also looks as if usage-vec-len is just the count of usage-indices, so no need to specify that in a global def when you can take care of that in the loop binding as well.
(loop [curr-reading reading
ui [0 0 0 0 0 0 0 0 0 0 0 0 0]
curr-idx (dec (count ui))]
body-of-expressions)
Related
I have built a long nested list having the following profile:
set my-list [A 1 2 3 4] [B 5 6 7 8] [C 9 10 11 12]
I'd like to apply the meancommand to the fourth item of each nested lists, so in the example to
4 8 12
but without building a list in loop that would look like [4 8 12] (to save computing time).
Is it possible ?
using let comp mean (item i item 4 (my-list)) or let comp mean (item 4 (my-list)) aren't obviously working.
The answer would be useful to other part of the model that I'm building.
Thanks for your time.
The map primitive is very well suited for these sorts of calculations with lists. It allows you to perform a reporter separately for each part of a list and then returns the results as a new list.
let test-list [1 2 3]
show map [x -> x + 1] test-list
;> [2 3 4]
In your case, you would use map to cycle through your list of lists, and use the item primitive to extract the necessary number from each sublist (map [x -> item 4 x ] my-list). This then returns them as a list of which you can take the mean.
to check-mean-2
let my-list [["a" 1 2 3 4] ["b" 5 6 7 8] ["c" 9 10 11 12]]
let my-mean mean map [x -> item 4 x ] my-list
print my-mean
end
EDIT: Although mine looks more efficient on first glance, Matteo's version actually runs quicker (at least on my machine)
globals [my-list]
to setup
set my-list [["a" 1 2 3 4] ["b" 5 6 7 8] ["c" 9 10 11 12]]
end
to check-mean
let timer-list []
repeat 10 [
reset-timer
repeat 1000000 [
let the-sum 0
let i 0
while [i < length my-list] [
set the-sum (the-sum + item 4 (item i my-list))
set i i + 1
]
let my-mean the-sum / i
]
let the-timer timer ; ~0.207
show the-timer
set timer-list lput the-timer timer-list
]
show word "mean: " (mean timer-list) ; 0.210
end
to check-mean-2
let timer-list []
repeat 10 [
reset-timer
repeat 1000000 [
let my-mean mean map [x -> item 4 x ] my-list
]
let the-timer timer
show the-timer
set timer-list lput the-timer timer-list
]
show word "mean: " (mean timer-list) ; 0.235
end
ANOTHER EDIT: Finally two more versions using reduce instead of map. Version 3 is the fastest of them all but you should take notice of the fact that my-list has a 0 added to it in this version. This might make is slightly less conveniet for other purposes. You can also add this 0 to it during the calculation as seen in version 4, but that drives up the time again.
to check-mean-3
set my-list [0 ["a" 1 2 3 4] ["b" 5 6 7 8] ["c" 9 10 11 12]]
let timer-list []
repeat 10 [
reset-timer
repeat 1000000 [
let my-sum reduce [ [x y] -> x + item 4 y] my-list
let my-mean my-sum / (length my-list - 1)
]
let the-timer timer
show the-timer
set timer-list lput the-timer timer-list
]
show word "mean: " (mean timer-list) ; 0.170
end
to check-mean-4
set my-list [["a" 1 2 3 4] ["b" 5 6 7 8] ["c" 9 10 11 12]]
let timer-list []
repeat 10 [
reset-timer
repeat 1000000 [
let my-new-list fput 0 my-list
let my-sum reduce [ [x y] -> x + item 4 y] my-new-list
let my-mean my-sum / (length my-list - 1)
]
let the-timer timer
show the-timer
set timer-list lput the-timer timer-list
]
show word "mean: " (mean timer-list) ; 0.226
end
First things first: did you mean to say that such nested list is built such as the one below?
set my-list [[A 1 2 3 4] [B 5 6 7 8] [C 9 10 11 12]]
Note the extra pair of square brackets, that make this actually a list of lists. Even if that was the case, NetLogo wouldn't let you use that syntax:
Either because A, B and C are lacking quotation marks if you intend them to be strings;
Or because, if A, B and C are variables, NetLogo expects literal values (we can get around this problem by using (list ...) instead of []).
In the first case, it would have to be:
set my-list [["a" 1 2 3 4] ["b" 5 6 7 8] ["c" 9 10 11 12]]
In the second case, it would have to be:
set my-list (list (list a 1 2 3 4) (list b 5 6 7 8) (list c 9 10 11 12))
All of the above just to make sure we are all on the same page (in general, please make sure that the code you post in your question is valid for the language you are asking about. As you can see, it would save a lot of time and space!).
Anyway I imagine that what you come up with is something of this type:
[["a" 1 2 3 4] ["b" 5 6 7 8] ["c" 9 10 11 12]]
I would use a while loop to iterate through the inner lists. You can create a local variable to keep track of the sum of the numbers you extract as you iterate through the inner lists, and then divide that sum by the number of times you extracted a number:
to check-mean
let my-list [["a" 1 2 3 4] ["b" 5 6 7 8] ["c" 9 10 11 12]]
let the-sum 0
let i 0
while [i < length my-list] [
set the-sum (the-sum + item 4 (item i my-list))
set i i + 1
]
print the-sum / i
end
From the answers above and adding a step in the procedure (mean and sd for groups of items having the same "region" in the list), here-below is my final code using map as the mean and sd are already calculated in a while-loop. Moreover, I assumed that calculating manually the standard deviation would create even more lists of list and complicate the code.
to create-successor-list
set successor-list map [inner-list -> (list inner-list 0 0 ) ] region-data
let i 0
while [i < length region-data] [
let current-item item i region-data
set temp-profitability-list (filter [current-inner-list -> (item 1 current-inner-list = current-item)] profitability-list )
set prof-mean mean map [x -> item 4 x ] temp-profitability-list
set prof-sd standard-deviation map [x -> item 4 x ] temp-profitability-list
set successor-list replace-item i successor-list (replace-item 1 item i successor-list (prof-mean))
set successor-list replace-item i successor-list (replace-item 2 item i successor-list (prof-sd))
set i i + 1
set temp-profitability-list [ ]
]
end
Is their a way in Clojure to go from an int to that int as a character, e.g. 1 to \1 ?
I have a string s and I want to parse out the digits that match a number n (n will always be 0 to 9)
e.g.
(let [n 1]
(filter #(= ??? %) "123123123"))
Where ??? would n as \n, e.g. would return "111"
Or maybe there is a better way to filter a string to only instance of a single digit?
The "java" way:
user=> (Character/forDigit 1 10) ; number and radix
\1
The "calculaty" way (add the int of \0 to it and then back to char):
user=> (char (+ 1 (int \0)))
\1
And as usual in Clojure, there's always a reduce one-line to solve the original problem: "I just want the count of how many times that digit appears."
(reduce (fn [m ch] (update m ch (fnil inc 0))) {} "123123123")
==> {\1 3, \2 3, \3 3}
A lot to unpack here, if you are new to Clojure.
Reduce is used to iterate over the String, counting occurrences of each character and storing it in a map.
From inner to outer:
(fnil inc 0) returns a function that runs inc with any argument provided. However, if the argument is nil, it will replace it with 0 instead. This is perfect for adding a new entry to the map.
update is used to look up an existing key ch in m and calculate a new value (by calling the function returned by (fnil inc 0)), i.e. if the ch is not in m this will run (inc 0) => 1, if ch is in m it will return the incremented counter.
(fn [m ch] ...) is the reducing function.
This is the most difficult part to understand. It takes two parameters.
The first is the last return value of this function (generated by an earlier iteration) or if it is the first time this function runs, the initial value provided: {} (there's also a third way to call reduce, see (doc reduce))
The second argument ch is the current character in the String provided (since String is a CharSequence and counts as a collection).
So the reducing function is called for each character and we just return the current map with an updated count for each character, starting with {}.
I am new to lisp. I am trying to read numbers from user and want to store it as a list. For example: if the user enters 1 2 3 4 5, then the list would contain 5 elements (1 2 3 4 5). I tried (parse-integer(read-line) :junk-allowed t) but it returns only the first element. How should I do this? Thanks.
Use read
The simplest option is to ask the user to enter the list (with the parens) and just call (read).
The second option is to put the parens yourself:
(read-from-string (concatenate 'string "(" (read-line) ")"))
safety and security
Note that the power of the Lisp reader can put you in trouble. E.g., if the user types #.(start-ww3) instead of (1 2 3) at your prompt, you might not reach your bomb shelter in time.
This means that you must bind *read-eval* to nil when calling read on text you do not control.
Call parse-integer repeatedly
Finally, you can call parse-integer in a loop
(defun parse-integers (s &optional (start 0))
(loop with num do
(setf (values num start) (parse-integer s :start start :junk-allowed t))
while num collect num))
or recursively:
(defun parse-integers (s &optional (start 0))
(multiple-value-bind (num end)
(parse-integer s :start start :junk-allowed t)
(and num (cons num (parse-integers s end)))))
I have a list with 20 items and I want to count the number of occurrences of each item in list. I know code below
to-report frequency [i lst]
report length filter [? = i] list
end
but I do not want to write 20 lines like
let C1 frequency 1 (list1)
let C2 frequency 2 (list1)
.
.
.
let C20 frequency 20 (list1)
That's:
map [frequency ? list1] n-values 20 [? + 1]
Sample run:
observer> set list1 [1 4 4 7 10 10 10 14]
observer> show map [frequency ? list1] n-values 20 [? + 1]
observer: [1 0 0 2 0 0 1 0 0 3 0 0 0 1 0 0 0 0 0 0]
For NetLogo 6, OP's function would be this:
to-report frequency [an-item a-list]
report length (filter [ i -> i = an-item] a-list)
end
Making a frequency list is revised like this:
map [ i -> frequency i list1] (n-values 20 [i -> i])
The range could be defined by maxInclude, maxExclude,minInclude,minExclude
(defn check-range [value maxInclude maxExclude minInclude minExclude] ...)
And the following should hold true.
(check-range 100 100 nil nil 10) ;; should return true since 100<=100 and 100>10
(check-range 100 nil 200 nil 10) ;; should return true since 100<200 and 100>10
(check-range 100 100 nil 101 nil) ;; should return false since 100<=101 is not true
Is there any simple solution? I am using a long code which looks like imperative solution. I think in clojure there must be some nice solutions.
update: my code is as below, but not complete and need help to complete it
(defn check-range [value maxInclude maxExclude minInclude minExclude]
(
let [value1 (if (and maxInclude (< value maxInclude)) false true)
value2 (if (and maxExclude (<= value maxExclude)) false true)
value3 (if (and minInclude (> value minInclude)) false true)
value4 (if (and minExclude (>= value minExclude)) false true)
]
;;; then how to combine value1,2,3,4 into final result as false or true.
)
)
)
I'm not sure what it means for a range to have both an inclusive and exclusive maximum (or similarly, minimum). It seems like those options should be mutually exclusive, which suggests you shouldn't let clients opt into choosing both. Otherwise, how do you decide if it's more important for inclusion to win, or exclusion? The choice seems like it would have to be pretty arbitrary.
I suggest that it would be better to have a different way of constructing the range. This would have the additional benefit of avoiding all the nil hoops you're talking about jumping through and let users be explicit about the kind of range that they're making.
Perhaps something like:
(defn make-range-checker [bottom-check top-check]
(fn [n]
(and (bottom-check n)
(top-check n))))
So that for your initial 3 examples, you'd do something like these to create range-checking functions that you could apply to your input of 100:
(make-range-checker (partial < 10) (partial >= 100))
(make-range-checker (partial < 10) (partial > 200))
(make-range-checker (partial <= 100) (partial > 101))
(your third example is not correct, incidentally: "100<=101 is not true")
Someone wanting to create a range that extends to infinity in either direction could simply pass a predicate that always returns true.
(make-range-checker (partial < 10) (constantly true))
(make-range-checker (constantly true) (partial > 10))