Looking for a function that would do something akin to the following:
(foo 3 2) => '( ( (1 1) (1 2) (1 3) )
( (2 1) (2 2) (2 3) ) )
Would there be any built-in function in DrRacket that accomplishes that?
The main tool that you want to use to get such things in Racket is the various for loops. Assuming that you want to create a list-based matrix structure, then this is one way to get it:
#lang racket
(define (foo x y)
(for/list ([i y])
(for/list ([j x])
(list (add1 i) (add1 j)))))
And since people raised the more general question of how to make foo create a matrix of any dimension, here's a generalized version that works with any number of arguments, and still returns the same result when called as (foo 3 2):
#lang racket
(define (foo . xs)
(let loop ([xs (reverse xs)] [r '()])
(if (null? xs)
(reverse r)
(for/list ([i (car xs)])
(loop (cdr xs) (cons (add1 i) r))))))
(Note BTW that in both cases I went with a simple 0-based iteration, and used add1 to get the numbers you want. An alternative way would be to replace
(for/list ([i x]) ... (add1 i) ...)
with
(for/list ([i (in-range 1 (add1 x)]) ... i ...)
)
Code:
(define (foo-makey const max data)
(let* ((i (length data))
(newy (- max i))
(newpair (cons const newy)))
(if (= max i)
data
(foo-makey const max
(cons newpair data)))))
(define (foo-makex xmax ymax data)
(let* ((i (length data))
(newx (- xmax i)))
(if (= xmax i)
data
(foo-makex xmax ymax
(cons (foo-makey newx ymax '()) data)))))
(define (foo x y)
(foo-makex y x '()))
Output:
> (foo 3 2)
'(((1 . 1) (1 . 2) (1 . 3)) ((2 . 1) (2 . 2) (2 . 3)))
I can't answer your question as-is because I don't understand how the nested lists should work for >2 arguments. AFAIK there is no built-in function to do what you want.
To start you off, here is some code that generates output without nested lists. As an exercise try adjusting the code to do the nested listing. And see if there's a way you can make the code more efficient.
;;can take in any number of arguments
(define (permutations . nums)
(foldl
(lambda (current-num acc)
(append-map
(lambda (list-in-acc)
(for/list ((i (build-list current-num (curry + 1))))
(append list-in-acc (list i))))
acc))
(list (list))
(reverse nums)))
Example 1:
> (permutations 3 2)
'((1 1) (1 2) (1 3) (2 1) (2 2) (2 3))
Example 2:
> (permutations 10)
'((1) (2) (3) (4) (5) (6) (7) (8) (9) (10))
Example 3:
> (permutations 2 3 4)
'((1 1 1)
(1 1 2)
(1 2 1)
(1 2 2)
(1 3 1)
(1 3 2)
(2 1 1)
(2 1 2)
(2 2 1)
(2 2 2)
(2 3 1)
(2 3 2)
(3 1 1)
(3 1 2)
(3 2 1)
(3 2 2)
(3 3 1)
(3 3 2)
(4 1 1)
(4 1 2)
(4 2 1)
(4 2 2)
(4 3 1)
(4 3 2))
(define (build-2d row col)
(build-list row (lambda(x) (build-list col (lambda(y) (list (+ x 1) (+ y 1))))))
Related
((1 2 3)
(2 3 4)
(3 4 5)
(4 5 6))
from
(1 2 3 4 5 6)
And what is the type of such operation?
What I tried:
(loop
:with l2 = '()
:with l1 = '(1 2 3 4 5 6)
:for i :in l1
:do (push (subseq l1 0 3) l2))
You're pushing the same sublist every time through the loop.
You can use :for sublist on to loop over successive tails of a list.
And use :collect to make a list of all the results, rather than pushing onto your own list
(loop
:for l1 on '(1 2 3 4 5 6)
:if (>= (length l1) 3)
:collect (subseq l1 0 3)
:else
:do (loop-finish))
Alternatively use map:
(let ((l '(1 2 3 4 5 6)))
(map 'list #'list l (cdr l) (cddr l)))
;; ((1 2 3) (2 3 4) (3 4 5) (4 5 6))
You can read it as:
for list l with values (1 2 3 4 5 6)
map over the list and its two successive cdrs
by applying #'list on the elements of the lists map is looping through in parallel
(stopping when shortest list is used up)
and collecting the results as/into a 'list
#WillNess suggested even simpler:
(let ((l '(1 2 3 4 5 6)))
(mapcar #'list l (cdr l) (cddr l)))
thanks! So then we could generalize using only map variants:
(defun subseqs-of-n (l n)
(apply #'mapcar #'list (subseq (maplist #'identity l) 0 n)))
(maplist #'identity l) is equivalent to (loop for sl on l collect sl).
However,
(loop for sl on l
for i from 0 to n
collect sl)
is better because it stops at n-th round of looping ...
First let's define a function take-n, which either returns n items or an empty list, if there are not enough items. It will not scan the whole list.
(defun take-n (n list)
(loop repeat n
when (null list) return (values nil nil)
collect (pop list)))
Then we move this function take-n over the list until it returns NIL.
(defun moving-slice (n list)
(loop for l on list
for p = (take-n n l)
while p
collect p))
Example:
CL-USER 207 > (moving-slice 3 '(1 2))
NIL
CL-USER 208 > (moving-slice 3 '(1 2 3))
((1 2 3))
CL-USER 209 > (moving-slice 3 '(1 2 3 4 5 6 7))
((1 2 3) (2 3 4) (3 4 5) (4 5 6) (5 6 7))
Here's a version of Barmar's answer (which should be the accepted one) which is a bit more general and only calls length once.
(defun successive-leading-parts (l n)
(loop repeat (1+ (- (length l) n))
for lt on l
collect (subseq lt 0 n)))
> (successive-leading-parts '(1 2 3 4) 3)
((1 2 3) (2 3 4))
> (successive-leading-parts '(1 2 3 4) 2)
((1 2) (2 3) (3 4))
Or the classical more C-like for-loop-ing with indexes to solve it.
But use it more on strings/vectors but less on lists, because its performance is
for lists quadratic
for vectors (strings!) linear, so preferably to be used with them!
credits and thanks to #WillNess who pointed both points out (see comments below).
(defun subseqs-of-n (ls n) ;; works on strings, too!
(loop :for i :from 0 :to (- (length ls) n)
:collect (subseq ls i (+ i n))))
So on vectors/strings use:
(subseqs-of-n "gattaca" 5)
;; ("gatta" "attac" "ttaca")
I have a code like below. It return list as (((1 . 2) (1 . 0)) ((1 . 2) (1 . 1)) ((1 . 2) (1 . 3)) ((1 . 2) (1 . 4)) ((1 . 2) (1 . 5)) ((1 . 2) (1 . 6)) ((1 . 2) (1 . 7)) ((1 . 2) (0 . 2)) ((1 . 2) (2 . 2)))
I wonder if I can rewrite generHod function in the way to make it return list like ((1.2 1.0) (3.4 4.2) (1.3 1.3)...)
(setf hod '())
(defun generHod (CurrX CurrY)
(dotimes (y 8)
(if (/= y CurrY)
(setf hod (append hod (list (append (list (cons CurrX CurrY))(list (cons CurrX y))))))
)
)
(dotimes (x 8)
(if (/= x CurrX)
(setf hod (append hod (list (append (list (cons CurrX CurrY))(list (cons x CurrY))))))
)
)
)
Firstly:
(setf hod '())
This is a bad way to define a global variable; try
(defparameter hod ())
But why use a global variable at all? The function can construct a new list and just return it. If the caller wants to stick it into a global variable, that's up to the caller; it's extraneous to the operation of the function.
(defun generHod ...)
The syntax generHod is not distinguished from GENERHOD or generhod in Common Lisp, under the default readtable. All those tokens produce the same symbol. It is best not to play mixed case games in Lisp identifiers; if you want multiple words, put in a dash like gen-hod. Usually generate is abbreviated all the way to gen by English speaking hackers, not gener. See the gensym funtion in Common Lisp, for instance.
In your function, there is a completely superfluous append:
(append
(list (cons CurrX CurrY))
(list (cons CurrX y))))
The pattern (append (list X0) (list X1) ... (list XN)) can be rewritten (list X0 X1 ... XN). You're making superfluous lists of things only to append them together to make one list, instead of just listing the things in the first place.
To get the values from integer to floating point, the float function can be used, and the loop macro provides an idiom for iterating and collecting items:
(defun gen-hod (curr-x curr-y)
(let ((cxy (list (float curr-x) (float curr-y)))) ;; allocate just once!
(nconc ;; destructive append: use with care
(loop for y from 1 to 8
when (/= y curr-y)
append (list cxy (list (float curr-x) (float y))))
(loop for x from 1 to 8
when (/= x curr-x)
append (list cxy (list (float x) (float curr-y)))))))
Hello i have to programm this fucntion in lisp:
(defun combine-list-of-lsts (lst)...)
So when executing the function i should get
(combine-list-of-lsts '((a b c) (+-) (1 2 3 4)))
((A + 1) (A + 2) (A + 3) (A + 4) (A-1) (A-2) (A-3) (A-4) (B + 1) (B + 2) (B + 3) (B + 4) (B-1) (B-2) (B-3) (B-4)(C + 1) (C + 2) (C + 3) (C + 4) (C-1) (C-2) (C-3) (C-4))
What i have now is:
(defun combine-list-of-lsts (lst)
(if (null (cdr lst))
(car lst)
(if (null (cddr lst))
(combine-lst-lst (car lst) (cadr lst))
(combine-lst-lst (car lst) (combine-list-of-lsts (cdr lst))))))
Using this auxiliar functions:
(defun combine-lst-lst (lst1 lst2)
(mapcan #'(lambda (x) (combine-elt-lst x lst2)) lst1))
(defun combine-elt-lst (elt lst)
(mapcar #'(lambda (x) (list elt x)) lst))
But what i get with this:
((A (+ 1)) (A (+ 2)) (A (+ 3)) (A (+ 4)) (A(-1)) (A(-2)) (A(-3)) (A(-4))...)
I dont know how to make this but without the parenthesis
The first thing is to look at this case:
(combine-list-of-lsts '((a b c)))
What should that be? Maybe not what your function returns...
Then I would look at the function combine-list-of-lsts. Do you need two IF statements?
Then look at combine-elt-lst. Do you really want to use LIST? It creates a new list. Wouldn't it make more sense to just add the element to the front?
Usually, when you want to reduce mutliple arguments into single result, you need function #'reduce. Your combination of lists has name cartesian n-ary product.
Following function:
(defun cartesian (lst1 lst2)
(let (acc)
(dolist (v1 lst1 acc)
(dolist (v2 lst2)
(push (cons v1 v2) acc)))))
creates cartesian product of two supplied lists as list of conses, where #'car is an element of lst1, and #'cdr is an element of lst2.
(cartesian '(1 2 3) '(- +))
==> ((3 . -) (3 . +) (2 . -) (2 . +) (1 . -) (1 . +))
Note, however, that calling #'cartesian on such product will return malformed result - cons of cons and element:
(cartesian (cartesian '(1 2) '(+ -)) '(a))
==> (((1 . +) . A) ((1 . -) . A) ((2 . +) . A) ((2 . -) . A))
This happens, because members of the first set are conses, not atoms. On the other hand, lists are composed of conses, and if we reverse order of creating products, we could get closer to flat list, what is our goal:
(cartesian '(1 2)
(cartesian '(+ -) '(a)))
==> ((2 + . A) (2 - . A) (1 + . A) (1 - . A))
To create proper list, we only need to cons each product with nil - in other words to create another product.
(cartesian '(1 2)
(cartesian '(+ -)
(cartesian '(a) '(nil))))
==> ((2 + A) (2 - A) (1 + A) (1 - A))
Wrapping everything up: you need to create cartesian product of successive lists in reversed order, having last being '(nil), what can be achieved with reduce expression. Final code will look something like this:
(defun cartesian (lst1 lst2)
(let (acc)
(dolist (v1 lst1 acc)
(dolist (v2 lst2)
(push (cons v1 v2) acc)))))
(defun combine-lsts (lsts)
(reduce
#'cartesian
lsts
:from-end t
:initial-value '(nil)))
There is one more way you can try,
(defun mingle (x y)
(let ((temp nil))
(loop for item in x do
(loop for it in y do
(cond ((listp it) (setf temp (cons (append (cons item 'nil) it) temp)))
(t (setf temp (cons (append (cons item 'nil) (cons it 'nil)) temp))))))
temp))
Usage:(mingle '(c d f) (mingle '(1 2 3) '(+ -))) =>
((F 1 +) (F 1 -) (F 2 +) (F 2 -) (F 3 +) (F 3 -) (D 1 +) (D 1 -) (D 2 +)
(D 2 -) (D 3 +) (D 3 -) (C 1 +) (C 1 -) (C 2 +) (C 2 -) (C 3 +) (C 3 -))
I have 2 numbers let's say number1=5 and number2=3 and I want to create a list in this form
((1(1 2 3)) (2(1 2 3)) (3(1 2 3)) (4(1 2 3)) (5(1 2 3)))
So the number1 indicates the number of the elements in the list and number2 indicates the total elements that will be as the second part of every element..
I have smth like this untill now
(define mylist '())
(define (pushlist item item2)
(do ((j 1 (+ j 1))) ((> j item2))
(set! mylist(list mylist (list item j)))))
(define (createlist number number2)
(do ((j 1 (+ j 1))) ((> j number))
(pushlist j number2)
))
(createlist 5 3)
Unfortunately it doesn't work.. It doesn't give the result I want.. It gives me this (((((((((((((((() (1 1)) (1 2)) (1 3)) (2 1)) (2 2)) (2 3)) (3 1)) (3 2)) (3 3)) (4 1)) (4 2)) (4 3)) (5 1)) (5 2)) (5 3))
There are many ways to solve this problem - for example, using explicit recursion, or using higher-order procedures. Your approach is not recommended, in Scheme you should try to avoid thinking about loops and mutation operations. Although it is possible to write such a solution, it won't be idiomatic. I'll try to explain how to write a more idiomatic solution, using explicit recursion first:
; create a list from i to n
(define (makelist i n)
(if (> i n)
'()
(cons i (makelist (add1 i) n))))
; create a list from i to m, together with
; a list returned by makelist from 1 to n
(define (makenumlist i m n)
(if (> i m)
'()
(cons (list i (makelist 1 n))
(makenumlist (add1 i) m n))))
; call previous functions
(define (createlist number1 number2)
(makenumlist 1 number1 number2))
Now, an even more idiomatic solution would be to use higher-order procedures. This will work in Racket:
; create a list from i to n
(define (makelist n)
(build-list n add1))
; create a list from i to m, together with
; a list returned by makelist from 1 to n
(define (makenumlist m n)
(build-list m
(lambda (i)
(list (add1 i) (makelist n)))))
; call previous functions
(define (createlist number1 number2)
(makenumlist number1 number2))
See how we can avoid explicit looping? that's the Scheme way of thinking, the way you're expected to solve problems - embrace it!
I don't think that your pushlist procedure is doing what you you expect it to.
(define (pushlist item item2)
(do ((j 1 (+ j 1)))
((> j item2))
(set! mylist (list mylist (list item j)))))
If you have a list (x y z) and you want to push a new value v into it, you'd do
(set! lst (cons v lst))
because (cons v (x y z)) == (v x y z). By doing
(set! mylist (list mylist (list item j)))
you're making mylist always have exactly two elements, where the first is a deeper and deeper nested list. Óscar López's answer gives a more idiomatic approach to this problem. Here's a similar idiomatic approach:
(define (range n)
; returns a list (1 ... n)
(let rng ((n n) (l '()))
(if (zero? n)
l
(rng (- n 1) (cons n l)))))
If the sublists (1 ... n) can all be the same list (i.e., the actual list object is the same), then you can create it just once:
(define (createlist m n)
(let ((sublist (range n)))
(map (lambda (main)
(list main sublist))
(range m))))
Otherwise, if they need to be distinct, you can generate one for each of 1 ... m:
(define (createlist m n)
(map (lambda (main)
(list main (range n)))
(range m)))
Maybe my title is a little bit messy..
I have a list in this form
(define a '( (1 3) (2 2) (3 3) (4 5) (5 1)))
and I want to decrement by 1, the second element for every pair which has the the first element in the given list...
Eg..
(updateA ( 1 3 4))
will result
( (1 2) (2 2) (3 2) (4 4) (5 1)
(define (updateA lst)
(for ((x lst))
(for ((y a))
(equal? x (car y)))
;;do something here
))
Here's one implementation:
(define (decrement-alist-values alist keys)
(map (lambda (ass)
(if (member (car ass) keys)
(list (car ass) (- (cadr ass) 1))
ass))
alist))
Example:
> (decrement-alist-values '((1 3) (2 2) (3 3) (4 5) (5 1))
'(1 3 4))
((1 2) (2 2) (3 2) (4 4) (5 1))
Joshua Taylor mentioned that my version technically didn't update the list via mutation. That is a fair point, so here is a mutating version:
(define (decrement-alist-values! alist keys)
(for-each (lambda (ass)
(when (member (car ass) keys)
(set-car! (cdr ass) (- (cadr ass) 1))))
alist))
Example:
> (define a `(,(list 1 3) ,(list 2 2) ,(list 3 3) ,(list 4 5) ,(list 5 1)))
> (decrement-alist-values! a '(1 3 4))
> a
((1 2) (2 2) (3 2) (4 4) (5 1))