(defclass schedule ()
((day :accessor schedule-day :initarg :day)))
(setf october
(make-array '(31)
:element-type 'schedule
:initial-element
(make-instance 'schedule :day 0)))
(setq searcher (read))
(setf (schedule-day (aref october (- searcher 1))) searcher)
(dotimes (i 31)
(format t "-month:10 day:~S~%" (schedule-day (aref october i))))
This is part of my october scheduling program.
This part should get the day I typed and change that day's day element, and print every october schedule.
however,
(setq searcher (read))
(setf (schedule-day (aref october (- searcher 1))) searcher)
I have trouble in this. if I type 17, then only 17th day of october should affected and printed like this,
-month:10 day:0
-month:10 day:0
...
-month:10 day:17
-month:10 day:0
...
but what I really got is
-month:10 day:17
-month:10 day:17
-month:10 day:17
...
why I can't change only one element? I managed to do this in c++ like,
october[searcher - 1].setDay(searcher);
It seems setf affects the class itself, not class object. can you help me? Thanks.
Your problem is that your array contains 31 pointers, each pointing to the same object.
Thus (setf (schedule-day (aref october a)) b) modifies that unique object.
You can achieve what you want by either encapsulating october so that the ith element is created only as necessary, or by initializing the array with something like
(apply #'vector (loop repeat 31 collect (make-instance 'schedule)))
or
(make-array 31 :initial-contents (loop repeat 31 collect (make-instance 'schedule)))
The root cause of your confusion is that you specified the array element-type and assumed that you created a "specialized" array.
Thus, despite the fact that you actually call (make-instance 'schedule) just once, you will have 31 objects in contiguous memory.
However, your implementation is not obligated to honor the
element-type specification in that way (it will create an array which
can hold the objects of the type you specified, but not necessarily
only those objects),
and what you actually got is a simple-vector.
PS. You should
use defvar or defparameter
instead of setq
or setf to define global
variables (like october), and you should name them
using
"earmuffs",
like *october*.
You can easily see that the array elements are pointing to just one CLOS object.
CL-USER 28 > (defclass foo () ())
#<STANDARD-CLASS FOO 4020002613>
CL-USER 29 > (make-array 3 :initial-element (make-instance 'foo))
#(#<FOO 402000AE9B> #<FOO 402000AE9B> #<FOO 402000AE9B>)
All objects have the same ID 402000AE9B.
In the next example the objects are different:
CL-USER 30 > (make-array 3 :initial-contents (list (make-instance 'foo)
(make-instance 'foo)
(make-instance 'foo)))
#(#<FOO 4020000B43> #<FOO 4020000B63> #<FOO 4020000B83>)
All have different IDs.
Related
This is the first time I have ever seen this compiler error does anyone know what it is? and why my function can't print my nested vectors.
(defvar *col-lookup* #.(let ((ht (make-hash-table)))
(loop for (key . value) in
'(
(A . 0) (B . 1) (C . 2)
(D . 3) (E . 4) (F . 5) (G . 6))
do (setf (gethash key ht) value))
ht))
;; vector of vectors
(defparameter *game-board*
(make-array 7 :initial-element (make-array 0 :initial-element 0)))
;;make move lookup character in table then push X onto vector of value of key
(defun move (c)
(let ((place (gethash c *col-lookup*)))
(cond ((oddp *turn-count*)
(push "X" (aref *game-board* place))
(incf *turn-count*))
((push "O" (aref *game-board* place))
(incf *turn-count*)))))
You are creating a very peculiar vector of vectors with the code:
(make-array 7 :initial-element (make-array 0 :initial-element 0)))
This code will create a vector of 7 elements, each of them a vector with 0 elements (i.e. an empty vector) (and note that giving the initial-element to 0 is useless because there are no elements to assign). If you print it you should see:
#(#() #() #() #() #() #() #())
which means exactly this, a vector with seven empty vectors. So if you try to access the internal vector with something like (aref (aref *game-board*) 1) 2) you get an error.
Finally note that in the code of the function move you use:
(push "X" (aref *game-board* place))
whose effect is not of modifying the internal vector at place place, but of replace the old value of (aref *game-board* place) with a cons of the string "X" and the old value of (aref *game-board* place), the empty vector.
I was able to print my vector of vectors by simply looping over it once. I still do not know what that error was but I haven't ran into it since.
(defun print-game ()
(loop for i from 0 to 6 do
(print (aref *game-board* i))))
Let's suppose I have an array - which I will call *my-array* - that looks like this:
#2A((1 2 3)
(4 5 6)
(7 8 9))
and I wish to apply some function f on the subarray
#2A((5 6)
(8 9))
I'd love to be able to write
(f (subarray *my-array* '(1 2) '(1 2))
where subarray takes as arguments:
the original array
a 2-element list with starting point and ending point on the 1st dimension
another 2-element list with starting point and ending point on the 2nd dimension
etc.
I am looking for some way to pass the subarray as argument to function f by reference (or by pointer?) instead of by value.
(The dumb way to address this would be to write a function that creates (in this specific case) a 2*2 array and loops over i and j copying values from the original array. However, if you are dealing relatively large arrays, this would be quite costly.)
I found there exists a cl-slice package but I do not get whether it copies values or accesses data by reference.
Common Lisp has Displaced Arrays which are exactly what you are asking about (see array-displacement &c).
However, in your case, displaces arrays are no help because:
Multidimensional arrays store their components in row-major order; that is, internally a multidimensional array is stored as a one-dimensional array, with the multidimensional index sets ordered lexicographically, last index varying fastest.
This means that your subarray is not a contiguous section of your main array, and, thus, you cannot create another array displaced to it.
PS. If you cannot figure out how cl-slice works, you can use time to see how much memory it uses and make your inference from that.
PPS. It is, in fact, not too hard to whip up something like what you want:
(defmacro slice (array &rest ranges)
"Return an accessor into ARRAY randing in RANGES."
(let ((args (loop for r in ranges collect (gensym "SLICE-ARG-")))
(arr (gensym "SLICE-ARRAY-")))
`(let ((,arr ,array))
(lambda ,args
(aref ,arr
,#(loop for arg in args and (lo hi) in ranges
for range = (- hi lo)
collect
`(progn
(unless (<= 0 ,arg ,range)
(error "~S is out of range [0;~S]" ,arg ,range))
(+ ,lo ,arg))))))))
(defparameter *my-array*
#2A((1 2 3)
(4 5 6)
(7 8 9)))
(defparameter f (slice *my-array* (1 2) (1 2)))
(loop for i from 0 to 1 do
(loop for j from 0 to 1 do
(format t " ~S" (funcall f i j)))
(terpri))
5 6
8 9
As others pointed out, you cannot use displaced arrays for matrices (maybe you could with non-standard functions). But all you need is to change how you interact with the original array. Here are some possibilities.
Sequences of displaced arrays
(defun area (matrix tlx tly brx bry)
;; you may also want to check that all coordinates are valid
;; inside current matrix. You could generalize this function for
;; more dimensions.
(assert (<= tlx tly))
(assert (<= brx bry))
(loop
for y from tly upto bry
collect (make-array (1+ (- brx tlx))
:displaced-to matrix
:displaced-index-offset
(array-row-major-index matrix y tlx))))
(tl means top-left, br means bottom-right).
Then, assuming you define your matrix as follows:
(defparameter *matrix* #2A((1 2 3)
(4 5 6)
(7 8 9)))
... the sub-matrix is obtained as follows:
(area *matrix* 1 1 2 2)
=> (#(5 6) #(8 9))
... and accessed like this:
(aref (nth ROW *) COL)
Any changes to *matrix* is reflected in one of the two displaced arrays, and inversely.
But if you coerce the resulting list as a vector, then you'll have a vector of arrays. This is different from multi-dimensional arrays, but gives you constant time access for rows:
(aref (aref area ROW) COL)
Wrapper closure
Another way to provide a restricted view of the original matrix is to create an accessor function that works only for the ranges of interest:
(defun sub-matrix (matrix tlx tly brx bry)
;; again, you should do more checks
(assert (<= tlx tly))
(assert (<= brx bry))
(lambda (x y &optional (value nil valuep))
(incf x tlx)
(incf y tly)
(assert (<= tlx x brx))
(assert (<= tly y bry))
(if valuep
(setf (aref matrix y x) value)
(aref matrix y x))))
This returns a closure which takes 2 or 3 arguments. The first two arguments are x and y coordinates relative to the inner matrix. When given a third argument, the closure sets the value. Otherwise, it gets the value.
This can be made more generic. I was partly inspired by sds's answer but tried to do things a little differently; here I can generate either a setter or a getter function. I also add some checks before creating the function and during the execution of the created function:
(defun slice-accessor (array ranges mode)
(let* ((dimensions (array-dimensions array))
(max-length (length dimensions)))
(check-type array array)
(loop
with r = (copy-list ranges)
for range = (pop r)
for (lo hi) = range
for d in dimensions
for x from 0
for $index = (gensym x)
collect $index into $indices
when range
do (assert (<= 0 lo hi d))
and collect `(check-type ,$index (integer 0 ,(- hi lo))) into checks
and collect `(incf ,$index ,lo) into increments
finally (let ((body `(apply #'aref ,array ,#$indices ())))
(return
(compile nil
(ecase mode
(:read `(lambda ,$indices
,#checks
,#increments
,body))
(:write (let (($v (make-symbol "VALUE")))
`(lambda (,$v ,#$indices)
(check-type ,$v ,(array-element-type array))
,#checks
,#increments
(setf ,body ,$v)))))))))))
CLOS
Once you have the above, you can provide a nice interface through objects. The setter and getter functions are updated whenever we change the ranges or the array being sliced:
(defclass array-slice ()
((array :initarg :array :accessor reference-array)
(ranges :initarg :ranges :accessor slice-ranges :initform nil)
(%fast-getter :accessor %fast-getter)
(%fast-setter :accessor %fast-setter)))
(flet ((update-fast-calls (o)
(setf (%fast-setter o)
(slice-accessor (reference-array o) (slice-ranges o) :write)
(%fast-getter o)
(slice-accessor (reference-array o) (slice-ranges o) :read))))
(defmethod initialize-instance :after ((o array-slice) &rest k)
(declare (ignore k))
(update-fast-calls o))
(defmethod (setf reference-array) :after (new-array (o array-slice))
(declare (ignore new-array))
(update-fast-calls o))
(defmethod (setf slice-ranges) :after (new-ranges (o array-slice))
(declare (ignore new-ranges))
(update-fast-calls o)))
(defgeneric slice-aref (slice &rest indices)
(:method ((o array-slice) &rest indices)
(apply (%fast-getter o) indices)))
(defgeneric (setf slice-aref) (new-value slice &rest indices)
(:method (new-value (o array-slice) &rest indices)
(apply (%fast-setter o) new-value indices)))
Examples
(defparameter *slice*
(make-instance 'array-slice :array *matrix*))
;; no range by default
(slice-aref *slice* 0 0)
=> 1
;; update ranges
(setf (slice-ranges *slice*) '((1 2) (1 2)))
(slice-aref *slice* 0 0)
=> 5
(incf (slice-aref *slice* 0 0) 10)
=> 15
*matrix*
=> #2A((1 2 3) (4 15 6) (7 8 9))
;; change array
(setf (reference-array *slice*) (make-array '(3 3) :initial-element -1))
(slice-aref *slice* 0 0)
=> -1
I don't think it is possible to do exactly what you want to do. In memory, multidimensional arrays are implemented as a single flat array with some metadata which is used to convert from the multidimensional interface to the flat one. In your case *my-array* would look like this:
#(1 2 3 4 5 6 7 8 9)
If you had the subarray you desired as a reference to the original array, it would look like this:
#(5 6 _ 8 9)
Which is impossible since you are trying to skip the 7 of the original array. If all of the desired elements were part of a contiguous sub-sequence, you would be able to use the :displaced-to argument of make-array in order to copy the sub-sequence by reference, but unfortunately, that is not the case.
So If I have a defclass object and I make an instance of it and place it inside an array. How do I get the value of its slots inside the array?
I've tried:
(slot-value (aref *array* 0) :name)
I guess I am just not understanding how to access an object that is inside an array.
I can print the object in an unreadable form using (format t) but is there a way to print an object and all the slots in a form I can actually understand?
(defun generate-object (name)
(let ((a (make-instance 'person
:name name)))
(setf (aref *array* 0) a)))
it places the object inside the array but it seems that the slot is not being created?
This causes the problem:
(defclass person ()
((name :accessor name
:reader read-name
:initarg :name)))
(defvar *array* 0)
(setf *array* (make-array 20))
(defun generate-object (name)
(let ((a (make-instance 'person
:name name)))
(setf (aref *array* 0) a)))
The slot name needs to be a symbol that is syntactically valid as a variable name. Try 'name instead of :name .
(slot-value (aref *array* 0) 'name)
Look at the examples here.
While possible, it is not recommended to use slot-value outside of the low-level class-specific code (like initialize-instance methods etc.).
You should instead add accessors to your slots and use those. For example:
(defclass foo ()
((bar :reader foo-bar
:initarg :bar)))
This defines a class foo with a slot bar. You can initialize the slot upon object instantiation with the :initarg name:
(let ((my-foo (make-instance 'foo :bar "baz")))
#| whatever |#)
You can read the slot value with the defined :reader:
(let ((my-foo (make-instance 'foo :bar "baz")))
(foo-bar my-foo))
It doesn't matter where you get your foo from, of course. Imagine you have an array foo-array which is filled with foos. To get the bar slot value of the fourth foo in that array:
(foo-bar (aref foo-array 3))
If you also want to set the value, use an :accessor instead of the :reader slot option.
Then you can use it as a place:
(let ((my-foo (make-instance 'foo)))
(setf (foo-bar my-foo) "quux"))
Is there any simplier way to find the last element of an array in clojure except this function?
(fn [l] (if (empty? (rest l)) (first l) (recur (rest l))))
For vectors, use peek for constant time
user=> (peek [1 2 3 4 5])
5
For Java arrays,
user=> (let [a (to-array [1 2 3 4 5])] (aget a (dec (alength a))))
5
For a general collection, you can get the last item in linear time with last. It is defined similarly to what you have done.
user=> (source last)
(def
^{:arglists '([coll])
:doc "Return the last item in coll, in linear time"
:added "1.0"
:static true}
last (fn ^:static last [s]
(if (next s)
(recur (next s))
(first s))))
The simplest way is to use (last l) that works in linear time (http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/last)
Another possibility is to reverse your collection and take the first element: ((comp first reverse) l). But that's rather slow as reverse returns a non-lazy sequence. Note: comp returns a composition of its arguments (functions) (http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/comp)
You can also convert the collection to a vector first and then apply peek: ((comp peek vec) l). This should have a better performance.
Another one: determine the length of your collection and take the last element (#(nth % (dec (count %))) l).
These functions work for all collection types (e.g. vectors, lists, ...). There are no arrays per se in Clojure (except you want to use Java arrays).
I have a list of elements. Each element is structured as followed:
('symbol "string" int-score)
An example list:
(list (list 'object1 "wabadu" 0.5)
(list 'object2 "xezulu" 0.6)
(list 'object1 "yebasi" 0.5)
(list 'object1 "tesora" 0.2))
I want to retrieve the maximum values for a specific symbol. When I search with the symbol object2, I should get back:
('object2 "xezulu" 0.6)
If I search with object1, I should get back:
(('object1 "wabadu" 0.5) ('object1 "yebasi" 0.5))
I want to collect all the highest elements of a specific object. What I can do is this: assume that the above list is the list used below and that I'm searching for object1. I can retrieve all elements of a specific object:
(loop for element in list
when (equal 'object1 (first element))
collect element)
I can also retrieve one highest element of the list:
(loop for element in list
when (equal 'object1 (first element))
maximize (third element))
However, this will only return one element. What I want is all maximum elements. I've tried some combinations with collect and maximize, but my knowledge on the syntax is little. Is there a way to collect all the highest elements in a ‘simple’ function?
A sketch of a LOOP-based version:
(defun mymax (target list &aux result max)
(loop for (item name value) in list
when (eql item target)
do (cond ((or (null result)
(> value max))
(setf result (list (list item name value))
max value))
((= value max)
(push (list item name value) result))))
result)
This will create a hash-table with the keys being the symbols and the values being arranged in the way (maximum . (list of strings corresponding to maximum))
(let ((data (list (list 'object1 "wabadu" 0.5)
(list 'object2 "xezulu" 0.6)
(list 'object1 "yebasi" 0.5)
(list 'object1 "tesora" 0.2))))
(loop
:with table := (make-hash-table)
:for (item string num) :in data :do
(destructuring-bind (&optional max strings)
(gethash item table)
(cond
((or (null max) (< max num))
(setf (gethash item table) (list num (list string))))
((= max num)
(setf (cdr strings) (cons string (cdr strings))))))
:finally (return table)))
;; #<HASH-TABLE {1005C6BE93}>
;; --------------------
;; Count: 2
;; Size: 16
;; Test: EQL
;; Rehash size: 1.5
;; Rehash threshold: 1.0
;; [clear hashtable]
;; Contents:
;; OBJECT1 = (0.5 ("wabadu" "yebasi")) [remove entry]
;; OBJECT2 = (0.6 ("xezulu")) [remove entry]
I think your life would be later easier with this hash table then with the data structure you currently have.
You can do that by looping through the list once for selecting all the sublists with the right first elements and determining the maximum (you can use into to let loop accumulate multiple values), and then a second loop in the finally clause go through the selection and now select only those with the maximum score:
(loop for triple in *l*
for (key nil score) = triple
when (eq key 'object1)
collect triple into selection
and maximize score into max-score
finally (return (loop for triple in selection
when (eql (third triple) max-score)
collect triple)))
Edit: Alternatively, instead of a second loop, the delete function can be used here quite concisely:
(loop for triple in *l*
for (key name score) = triple
when (eq key 'object1)
collect triple into selection
and maximize score into max-score
finally (return (delete max-score selection
:test #'/=
:key #'third)))
The maximize returns only one element. You can sort all the list by the 3rd component and then gets the front one(s). Like this:
;;; suppose a copy of the data is stored in l
;; get all 'object1 and sort them
(setf l (sort (remove-if-not
(lambda (x) (equal (first x) 'object1)) l)
#'> :key #'third))
;; remove the ones with smaller value than the first one
(setf l (remove-if
(lambda (x) (< (third x) (third (first l)))) l))
Abstract your data to create basic building blocks; combine building blocks into your needed functionality:
(defun make-foo (type name score)
(list type name score))
(defun foo-type (foo) (elt foo 0))
;; ...
(defun make-foos (&rest foos)
foos)
(defun foos-find-if (foos predicate)
;; return all foos satisfying predicate
)
(defun foos-maximize (foos orderer)
;; return the maximum foo (any one)
)
(defun foos-find-if-maximized (foos)
(foos-find-if foos
(let ((max (foos-maximize foos #'foo-score)))
(lambda (foo)
(= (foo-score max) (foo-score foo))))))
Here is an approach by first saving symbol-list that only contains the lists with the search object. Then we can easily get the maximum value and remove those lists with a smaller value.
(defun foo (symbol list)
(let* ((symbol-list (remove-if-not #'(lambda (l) (eq (first l) symbol))
list))
(max (apply #'max (mapcar #'third symbol-list))))
(remove-if-not #'(lambda (l) (= (third l) max))
symbol-list)))
We can call it: (foo 'object1 l)
As a rule of thumb, if you are really wanting to boil down a list of things into a single result, there should be a nice way to do this with reduce.
And there is:
(defun collect-maxima-by-third (list)
(reduce
#'(lambda (max-list next-element)
(let ((max-value (third (first max-list)))
(next-value (third next-element)))
(cond ((< max-value next-value)
(list next-element))
((= max-value next-value)
(cons next-element max-list))
(t max-list)))) ; the greater-than case
(rest list)
:initial-value (list (first list))))
It's not perfect, as if you give it an empty list it will give you a list containing an empty list instead of just an empty list, but you can easily add a case for this if you think that will happen often.
This type of technique (maybe not this exact example) is detailed in various texts on functional programming; some Haskell texts do a particularly good job (Learn You a Haskell comes to mind).