I am working with someone using elisp and we have been struggling to use multi-dimensional arrays.
The problem is that if we try to set a value using
(setf (elt (elt m-array 0) 0) 5))
We end up getting something like this
[[0 0 0 5] [0 0 0 5] [0 0 0 5] [0 0 0 5]]
which is not what we want. Now Common Lisp has the support we need to get around this. Unfortunately though, we are only able to work with elisp. My question is, given that we only have elisp, how can we work around this such that we instead only set one vector in the vectors.
Like:
[[0 0 0 5] [0 0 0 0] [0 0 0 0] [0 0 0 0]]
While Common Lisp has multidimensional arrays, Emacs Lisp has only vectors (one-dimensional arrays).
You are trying to emulate multidimensional arrays in ELisp using vectors of vectors (which is, indeed, a fairly standard trick), but you need to be careful to avoid "aliasing" - i.e., you need to make sure that your nested arrays are not identical objects.
Your problem indicates is that
(eq (aref m-array 0) (aref m-array 1))
==> t
because you probably created your m-array like this:
(setq m-array (make-vector 5 (make-vector 5)))
You need to create your m-array like this:
(setq m-array (make-vector 5 nil))
(dotimes (i 5)
(setf (aref m-array i) (make-vector 5 0)))
Related
Hi all I am new at learning Scheme and often have issues with making parallels between an imperative language and a functional language.
For example if I had had two arrays.
A = [1 2 3]
B = [4 5 6]
If I wanted to create a new array with the elements of A multiplied by each element in B I could simply do something like (pseudo-code):
for(int i = 0; i < A.length; i++)
for(int j = 0; j < B.length, j++)
arr.push(A[i]*B[j])
Which would give back:
arr = [4 5 6 8 10 12 12 15 18]
What would be some ways to approach this problem in a functional language?
In Scheme, the most common data structure is the linked list. Unless you have to access elements by index, it's always preferred to use lists, as there are countless built-in procedures for handling lists, that make easy to implement most algorithms without ever using an index. Just remember that for efficient access by index, using a vector would be a better idea.
Having said that, and depending on the Scheme dialect that you're using, the solution can be as simple as this (in Racket, see the documentation):
(define a '(1 2 3))
(define b '(4 5 6))
(for*/list ([x a] [y b])
(* x y))
=> '(4 5 6 8 10 12 12 15 18)
Alternatively, using only standard Scheme:
(apply append
(map (lambda (x)
(map (lambda (y) (* x y))
b))
a))
In Scheme and Racket arrays (array: a data structure indexed by a natural number) is represented using vectors.
(define as (vector 1 2 3))
(define bs (vector 4 5 6))
To make a loop-inside-a-loop we will use a variant of for*.
Plain for* works like this:
(for* ([a as] [b bs])
(displayln (* a b))))
Here a runs through the elements of the vector as and b runs through the elements in bs. Since for* is used, the b-loop runs inside the a-loop.
If for is used instead the loops run in parallel (try it).
Now since we want to collect the element, we can use for*/vector which stores the generated elements in a vector:
(for*/vector ([a as] [b bs])
(* a b)))
For efficiency reason, one can write:
(for*/vector ([a (in-vector as)] [b (in-vector bs)])
(* a b)))
This will generate sligthly more efficient code.
However
(for*/vector ([a as] [b bs])
(* a b)))
will also work if as and bs are lists.
It is working fine and I've checked manually that everything is running, but I now need to figure out how to print out the answer in a chessboard like fashion, where I have an nxn board of 0's and 1's, where 1's are the queens. I am using vectors and for example lets say I run nq-bt for a 5x5 board I get the answer: #(0 2 4 1 3)
nq-bt is the method that gives me the answer above
Here is my pseudocode for trying to get this to work:
(define (print-answer n)
(make n equal to the returned vector of method (nq-bt))
(loop until it hits end of the returned vector_length)
(set value equal to (vector ref of n (*variable used for first loop)))
(loop again the length of returned vector_length)
(print 0's until hits vector ref's value, then print 1, then print 0's till end of loop)
(print newline)))))
I know this is insane pseudocode, but my problem is that I'm not used to scheme and there isn't too much documentation on how I could do any of this. Any help would be greatly appreciated.
You didn't mention which Scheme interpreter you're using, so first I'll show you a generic solution that uses standard procedures. For starters, we must decide how are we going to loop over the vector (say, using named lets).
Also notice that I changed the input parameter, it's easier if we pass the board's solution, besides I don't see how you can use the size n of the board if nq-bt doesn't receive it as a parameter (I hope nq-bt isn't obtaining n from a global define, that wouldn't be right):
(define (print-answer board)
(let outer-loop ((i 0))
(cond ((< i (vector-length board))
(let ((queen (vector-ref board i)))
(let inner-loop ((j 0))
(cond ((< j (vector-length board))
(display (if (= queen j) 1 0))
(display " ")
(inner-loop (+ j 1))))))
(newline)
(outer-loop (+ i 1))))))
Now, if you're lucky and use Racket we can write a simpler and more idiomatic implementation without all the kludge of the previous solution:
(define (print-answer board)
(for ([i (in-range (vector-length board))])
(let ([queen (vector-ref board i)])
(for ([j (in-range (vector-length board))])
(printf "~a " (if (= queen j) 1 0))))
(newline)))
Either way we can call print-answer with the result returned by nq-bt. For example:
(print-answer '#(0 2 4 1 3))
1 0 0 0 0
0 0 1 0 0
0 0 0 0 1
0 1 0 0 0
0 0 0 1 0
I think I just use setq (or setf, I'm not really sure the difference), but I don't understand how to reference the [i][j]-th element in an array in lisp.
My start condition is this:
? (setq x (make-array '(3 3)))
#2A((0 0 0) (0 0 0) (0 0 0))
I want to alter, say, the 2nd item of the 3rd "row" to give this:
? ;;; What Lisp code goes here?!
#2A((0 0 0) (0 0 0) (0 "blue" 0))
The following, which I would have thought close, gives an error:
(setq (nth 1 (nth 2 x)) "blue")
So what's the correct syntax?
Thanks!
I think proper way is to use setf with aref like this:
(setf (aref x 2 1) "blue")
For more details see reference.
You can find a dictionary of the ARRAY operations in the Common Lisp HyperSpec (the web version of the ANSI Common Lisp standard:
http://www.lispworks.com/documentation/lw50/CLHS/Body/c_arrays.htm
AREF and (SETF AREF) are documented here:
http://www.lispworks.com/documentation/lw50/CLHS/Body/f_aref.htm
The syntax to set an array element is: (setf (aref array &rest subscripts) new-element).
Basically if you want to set something in Common Lisp, you just need to know how to get it:
(aref my-array 4 5 2) ; access the contents of an array at 4,5,2.
Then the set operation is schematically:
(setf <accessor code> new-content)
This means here:
(setf (aref my-array 4 5 2) 'foobar) ; set the content of the array at 4,5,2 to
; the symbol FOOBAR
The correct invocation is
(setf (aref x 2 1) "blue")
setq is used when you're assigning to a variable. Only setf knows how to "reach into" compound objects as with setting a value in your array. Of course, setf also knows how to assign to variables, so if you stick with setf you'll always be okay.
If I have the following list:
(define thelist '(0 1 0 0 7 7 7))
How can I write a function that returns a new list in which the value in the requested cell is replaced.
Example:
(set-cell thelist 2 4)
This would return a new list with the same values, but in cell (2) there will be the value 4 instead of 1:
(0 4 0 0 7 7 7)
HtDP provides a really concrete methodology for solving this kind of problem. For this problem, your job is going to be to write down the template for lists, then to stare at it until you can see what the arguments to the recursive call should be, and what the results will be. I'm hoping that you've solved a bunch of warm-up problems on lists--compute the length of a list, count the number of 6's in the list, etc.
Although you can implement the requested functionality with lists, the natural way to solve that problem is to use a vector, and remember that in Scheme indexes start in 0 (that's why the second argument for vector-set! is a 1 and not a 2):
(define thevector (vector 0 1 0 0 7 7 7))
; thevector is #(0 1 0 0 7 7 7)
(vector-set! thevector 1 4)
; thevector is #(0 4 0 0 7 7 7)
Now, if you definitely need to use a list, something like this would work:
(define (set-cell lst idx val)
(cond ((null? lst) '())
((zero? idx) (cons val (cdr lst)))
(else (cons (car lst)
(set-cell (cdr lst) (sub1 idx) val)))))
And you'd call it like this:
(define thelist '(0 1 0 0 7 7 7))
(set-cell thelist 1 4)
> (0 4 0 0 7 7 7)
Again, I'm using 0-based indexing, as is the convention. Also notice that thelist was not modified, instead, set-cell returns a new list with the modification.
Other people have mentioned the 0-based indexes convention. I'll assume 0-based indexes, then.
The other answers you've gotten are wrong, given how you stated your problem. I'll cite the key point in your question (my emphasis):
This would return a new list with the same values, but in cell (2) there will be the value 4 instead of 1.
The answers you've been given are modifying a list in place, not returning a newly constructed list while leaving the original intact!
Here's a correct (though suboptimal) solution:
(define (set-list index new-value list)
(if (= index 0)
(cons new-value (cdr list))
(cons (car list)
(set-list (- index 1) new-value (cdr list))))))
I didn't bother to put in error checking here (e.g., if somebody passes in the empty list, or a list with too few elements relative to index, or a negative index).
Here is an approach using an auxiliary function that starts the count from 0. On each recursion, the count is incremented, and the list is shortened.
If the desired index is hit, the recursion can stop. If it gets to the end of the list without hitting the index, the original list is returned.
(define (set-cell ls ind val)
(define (aux c ls)
(cond ((null? ls) ls)
((= c ind) (cons val (cdr ls)))
(else (cons (car ls) (aux (+ c 1) (cdr ls))))))
(aux 0 ls))
What a mess above!! Keep it simple: Scheme has list-set! for this.
Example:
(define ls (list 1 2 3 4 5))
(list-set! ls 0 "new")
(list-set! ls 3 "changed")
(list-ref ls 0)
=> "new"
ls
=> '("new" 2 3 "changed" 5)
However, you might want to limit assignments on lists. Vectors are faster for this since you don't need to traverse the previous elements. Use lists whenever you can't specify the length before construction or when the length is continously changed.
I want to take an interval of a vector in Scheme. I know there is a procedure named vector->values, but seems like it returns each element separately, while I want to get the result as a vector. How can I achieve this?
> (vector->values (vector 1 2 3 4 5) 0 3)
1
2
3
while I need:
#(1 2 3)
If you're using PLT, you have a few easy ways to get this:
(define (subvector v start end)
(list->vector (for/list ([i (in-vector v start end)]) i)))
(define (subvector v start end)
(build-vector (- end start) (lambda (i) (vector-ref v (+ i start)))))
(define (subvector v start end)
(define new (make-vector (- end start)))
(vector-copy! new 0 v start end)
new)
The last one is probably going to be the fastest. The reason that there is no such operation that is built-in is that people usually don't do that. When you're dealing with vectors in Scheme, you're usually doing so because you want to optimize something so returning a vector and a range instead of allocating a new one is more common.
(And if you think that this is useful, please suggest it on the PLT mailing list.)
The Scheme R6RS standard has make-vector, vector-ref, vector-set! and vector-length. With that you can write your own function subvector, which does not seem to be part of R6RS (!). Some Scheme implementation have something like subvector already.
You can also switch to Common Lisp, which provides the function SUBSEQ in the standard.
Here is a portable R6RS version using SRFI 43:
#!r6rs
(import (rnrs base)
(prefix (srfi :43) srfi/43:))
(srfi/43:vector-copy (vector 1 2 3 4 5) 0 3)
#lang scheme
(define (my-vector-value v l h c)
(if (and (>= c l) (< c h))
(cons (first v) (my-vector-value (rest v) l h (add1 c)))
empty))
(list->vector (my-vector-value (vector->list (vector 1 2 3 4 5)) 0 3 0))
Ghetto? Yes, very. But it only took two minutes to write and gets the job done.
(I find it's generally easier to play with lists in Scheme)
you want subvector:
(subvector (vector 1 2 3 4 5) 0 3)