I got a list of lists in racket and have to transpose them.
(: transpose ((list-of(list-of %a)) -> (list-of (list-of %a))))
(check-expect (transpose (list (list 1 2 3)
(list 4 5 6)))
(list (list 1 4)
(list 2 5)
(list 3 6)))
(define transpose
(lambda (xs)
(cond
((empty? xs)empty)
((pair? xs)(make-pair (make-pair (first(first xs)) (make-pair (first(first(rest xs)))empty)) (transpose (rest(rest xs))))))))
That's my code at the moment.
I think the problem is in the recursive call (correct me if I'm wrong please).
The actual outcome is (list (list 1 4)). The rest seems kinda ignored.
It would really help me, if somebody knows the problem, or has a tip.
The simplest definition of transpose is:
(define (transpose xss)
(apply map list xss))
Why does it work?
(apply map list '((a b) (d e))
= (apply map List '((a b) (d e)) ; use List rather than list
= (map List '(a b) '(d e))
= (list (List 'a 'd) (List 'b e))
= '((a d) (b e))
Here List is spelled with capital letters only to show which list was given by the user and which was produced by map.
Here is a less "clever" solution. It uses that the first column of
a matrix becomes the first row in the transposed matrix.
(define transpose
(lambda (xss)
(cond
[(empty? xss) empty]
[(empty? (first xss)) empty]
[else (define first-column (map first xss))
(define other-columns (map rest xss))
(cons first-column
(transpose other-columns))])))
(define (transpose xss)
(apply map list xss))
If you are, like me, new to Scheme, you'll wonder how the apply map list trick works.
It all boils down to understanding apply and map.
First, apply does its job. It takes a function, some fixed arguments and a list of arguments.
It calls the function with the fixed arguments followed by the flattenned list arguments.
So:
(apply map list '((1 2) (3 4)))
^^^^^^^^^^^^^^-- list of arguments
^^^^ ---------------- a fixed argument
^^^ --------------------- function
evaluates to:
(map list '(1 2) '(3 4))
Note how the list of lists is turned into two lists.
Now map accepts an N-argument function and N lists of equal length. Then it returns a list, where each element is an application of the function.
For example
(map + '(1 2) '(3 4))
evaluates to:
(list (+ 1 3) (+ 2 4))
In the transpose trick the function is simply list, so:
(map list '(1 2) '(3 4))
evaluates to:
(list (list 1 3) (list 2 4))
where the first list constructs a list because map always returns a list and the other two are invocations of the passed list function.
for/list can be used sequentially to create a list of lists with transposed items:
(define (transpose_ lol) ; lol is list of lists
(for/list ((i (length (list-ref lol 0)))) ; loop for length of first inner list
(for/list ((il lol)) ; for each inner list (il)
(list-ref il i)))) ; get its item
Testing:
(transpose_ (list (list 1 2 3)
(list 4 5 6)))
Output:
'((1 4) (2 5) (3 6))
(define (tr ls)
(if (empty? (car ls)) empty
(if (null? ls) empty
(cons (map car ls) (tr (map cdr ls))))))
Related
So in Scheme, if I make a list as an argument, how would I go about evaluating that list to itself in the same order?
Would I just write:
(define (function list)
(list)
I don't really understand this.
Your question lacks an example.
Is this what you want:
(define (f . args)
args)
It can be used like this:
> (f 1 2 3)
(1 2 3)
If you have a list and a function which 'evaluates' elements of that list and you want to construct another list which is the result of calling that function on each element of the list then what you are doing is called mapping the function over the list and the function do do that is called map. Given the following two definitions:
(define course-names '((1 "Exploding buckets 101")
(2 "Squirrel cooking 201")
(4 "Flamethrower maintenance 211")))
(define (course->name c)
(let ((found (assq c course-names)))
(if found (second found) "UNKNOWN SECRET COURSE")))
Then
> (map course->name '(1 2 3 4))
'("Exploding buckets 101"
"Squirrel cooking 201"
"UNKNOWN SECRET COURSE"
"Flamethrower maintenance 211")
It's worth seeing how you can write things like map: here is one way:
(define (simple-map f l)
(define (simple-map-loop tail accum)
(if (null? tail)
(reverse accum)
(simple-map-loop (rest tail) (cons (f (first tail)) accum))))
(simple-map-loop l '()))
or:
(define (f lst)
lst)
used as:
(f '(1 2 3))
;; '(1 2 3)
I have a circular list, eg: #0=(1 2 3 4 . #0#).
What I want to do is to insert a new element (x) into this list so that the outcome is #0=(x 1 2 3 4 . #0#). I have been trying using this code (x is the circular list):
(define (insert! elm)
(let ((temp x))
(set-car! x elm)
(set-cdr! x temp)))
However, I think that set-cdr! is not working like I want it to. What am I missing here? Maybe I am way off?
The easiest way to prepend an element to a list is to modify the car of the list, and set the cdr of the list to a new cons whose car is the original first element of the list and whose cdr is the original tail of the list:
(define (prepend! x list) ; list = (a . (b ...))
(set-cdr! list (cons (car list) (cdr list))) ; list = (a . (a . (b ...)))
(set-car! list x)) ; list = (x . (a . (b ...)))
(let ((l (list 1 2 3)))
(prepend! 'x l)
(display l))
;=> (x 1 2 3)
Now, that will still work with circular lists, because the cons cell (i.e., pair) that is the beginning of the list remains the same, so the "final" cdr will still point back to object that is the beginning. To test this, though, we need some functions to create and sample from circular lists, since they're not included in the language (as far as I know).
(define (make-circular list)
(let loop ((tail list))
(cond
((null? (cdr tail))
(set-cdr! tail list)
list)
(else
(loop (cdr tail))))))
(define (take n list)
(if (= n 0)
'()
(cons (car list)
(take (- n 1)
(cdr list)))))
(display (take 10 (make-circular (list 1 2 3))))
;=> (1 2 3 1 2 3 1 2 3 1)
Now we can check what happens if we prepend to a circular list:
(let ((l (make-circular (list 1 2 3))))
(prepend! 'x l)
(display (take 15 l)))
;=> (x 1 2 3 x 1 2 3 x 1 2 3 x 1 2)
Since you're trying to prepend an element to a circular list, you need to do two things:
Insert a new cons cell at the front of the list containing the additional element. This is easy because you can just perform a simple (cons elm x).
You also need to modify the recursive portion of the circular list to point at the newly created cons cell, otherwise the circular portion will only include the old parts of the list.
To perform the latter, you need a way to figure out where the "end" of the circular list is. This doesn't actually exist, since the list is, of course, circular, but it can be determined by performing an eq? check on each element of the list until it finds an element equal to the head of the list.
Creating a helper function to do this, a simple implementation of insert! would look like this:
(define (find-cdr v lst)
(if (eq? v (cdr lst)) lst
(find-cdr v (cdr lst))))
(define (insert! elm)
(set! x (cons elm x))
(set-cdr! (find-cdr (cdr x) (cdr x)) x))
I'm trying to create a list containing all the values of a column from lists of lists resembling a matrix.
The list should contain only numbers and guess-number of a
(define-struct guess (symbol number))
puzzle1:
(list
(list 'a 'b 'b 'c)
(list 'a 2 1 4)
(list 'f 3 'g 'g)
(list 'f 'h 'i 'i))
The parameters are the matrix and a position, so:
(check-expect (used-in-column puzzle1 (make-posn 0 1)) (list 2 3))
(define-struct puzzle (size board constraints))
where the board part is the puzzle1 example needed above
I can create a list with only the numbers, but seem unable to alter the code so it adds any guess-number to the list
so here's an example with a guess inside of it, where the output given by my code is empty
(check-expect (used-in-column puzzle1partial2 (make-posn 0 1)) (list 2))
Where the puzzle-board is
(list
(list (make-guess 'a 2) 'b 'b 'c)
(list 'a 2 1 4)
(list 'f 3 'g 'g)
(list 'f 'h 'i 'i))
So far my code looks like this:
(define (used-in-column puz pos)
(local [(define (columns board pos)
(cond
[(empty? board) empty]
[else (cons (list-ref (first board) (posn-x pos))
(columns (rest board) pos))]))]
(cond
[(empty? puz) empty?]
[else (quicksort (filter number? (columns (puzzle-board puz) pos)) <)])))
I tried using if statements and other variants, but it ends up making my code a mess and not getting me any results.
Can anybody give me any advice on this?
As for you subject you can transpose with the standard unzip:
(define (unzip lsts)
(apply map list lsts))
(unzip '((1 2) (a b))) ; ==> ((1 a) (2 b))
If you just want one row you use list-ref:
(map (lambda (x) (list-ref x 1)) '((1 2) (a b))) ; ==> (2 b)
I really don't understand what your code is supposed to do and I can't run it either (lacks a stuct I think) so I leave it at this.
If I have a list and I map a lambda function over it how can I get a reference to the next or previous item while processing the current one?
(map (lambda (x) x) '(1 2 3))
How would I reference the previous or next element while processing x?
John McCarthy originally made maplist and it's defined in CL still and predates map(car). It's definition in Scheme would be something like:
(define (maplist fun lst)
(if (null? lst)
'()
(cons (fun lst) (maplist fun (cdr lst)))))
(maplist values '(1 2 3 4)) ; ==> ((1 2 3 4) (2 3 4) (3 4) (4))
It's slightly more difficult to get each element like map but if you need more than the first then it's perfect.
Start with your one list, construct two other lists, one 'shifted' right, and the other 'shifted' left. Like this:
(define (process func x)
(let ((to-front (cons 'front (reverse (cdr (reverse x)))))
(to-rear (append (cdr x) (list 'rear))))
(map func to-front x to-rear)))
Note that the stuff above with reverse is because map expects all lists to have the same length. So when adding to the front, you need to remove one from the tail.
Also, the provided func needs to accept three arguments.
> (process list '(a b c))
((front a b) (a b c) (b c rear))
You can always use map on two zipped lists, i.e.
(import (srfi srfi-1)) ; or use some zip implementation
(define a '(1 2 3 4 5))
(map (lambda (x) x)
(zip a
(append (cdr a) (list (car a)))))
which results in ((1 2) (2 3) (3 4) (4 5) (5 1)).
Of course, the above assumes "periodic" boundary conditions for the lists (you should modify the boundary conditions for your case).
And also you would need to modify the lambda to handle pairs of elements.
For simplicity let's take the case of two elements at a time -- the current and next one. So if you have (list 1 2 3), and a function that takes this and next args, you want it to be called with:
1 2
2 3
3 <some value, let's say 3>
You could write that concisely as:
(map f xs (append (drop xs 1) (list (last xs))))
However the drop and append-ing means that's not the fastest way to do it. Instead you could write a map-slide-pairs function to do it more directly:
#lang racket/base
(require racket/match)
;; map a list as "sliding pairs". For example:
;; (map-slide-pairs cons '(1 2 3)) ==> '((1 . 2)
;; (2 . 3)
;; (3 . 3))
(define (map-slide-pairs f xs #:last-val [last-val #f])
;; Concise implementation:
;; (map f xs (append (drop xs 1) (list (last xs)))))
;; Faster implementation:
(let loop ([xs xs])
(match xs
[(list) (list)]
[(list this) (list (f this (or last-val this)))]
[(list this next more ...) (cons (f this next)
(loop (cons next more)))])))
(module+ test
(require rackunit)
(check-equal? (map-slide-pairs cons '(1 2 3))
'([1 . 2][2 . 3][3 . 3]))
(check-equal? (map-slide-pairs cons '(1 2 3) #:last-val 100)
'([1 . 2][2 . 3][3 . 100])))
Hopefully you can see how to extend this and make a "map-slide-triples" function that would be called with the previous, current, and next elements of the list.
I come up again with my strange Scheme questions.
I have a definition that remove subelement(based on search occurrence) from a list and generate new list without it (based on this answer here).
(func '1 mylist) ; will return mylist without all sublists containing 1
All was working fine until I realized that I need to repeat my definition for each element in another list.
I call it recursively, but with every call I use the original list not the previous filtered.
Or with another words I want to achieve this:
(define filterList '(1 2 3))
(func '3 (func '2 (func '1 mylist) ); list without all sublists containig 1 2 3
I'm tottaly stuck. Thanks everyone for the help.
This is a basic loop over the lists of elements (elts) to remove from the initial list (lst):
(define (func2 elts lst)
(if (null? elts)
lst
(func2 (cdr elts) (func (car elts) lst))))
then
(func2 '(1 3) '(1 2 3))
=> '(2)
or, in Racket:
(define (func2 elts lst)
(for/fold ((res lst)) ((e (in-list elts)))
(func e res)))