I have a nested list: (def mylist '(+ '(+ 1 2) 3))
When I eval it, I get 6 as expected: (eval mylist)
How can I change the last element (3)? I'd like to get a list like this:
(+ (+ 1 2) 4)
I've tried
(list (butlast mylist) 4)
but it yields this:
((+ (+ 1 2)) 4)
i.e. the first part is nested in a list itself. How can I fix it? I'm building up that list datastructure recursively and at a later point I'll evaluate it via the eval function.
You can use the following:
(concat (drop-last mylist) '(4))
Related
In DrRacket to return the list without changing by using foldr done this way:
(foldr cons '() '(1 2 3))
However in Clojure reduce is fold left so how can I do this?
First I tried this:
(reduce cons '() '(1 2 3))
=> IllegalArgumentException Don't know how to create ISeq from: java.lang.Long clojure.lang.RT.seqFrom (RT.java:542)
Afterward I tried this:
(reduce conj '() '(1 2 3))
=> (3 2 1)
"=>" is the output in REPL
No I don't want to read how Clojure implements reduce. I already know that. This is a more specific question. I found the answer myself, I will post it.
In your second attempt you had to "flip" the arguments passed to cons for things to work:
(reduce #(cons %2 %1) '() '(1 2 3))
=> (3 2 1)
However, as you noticed, reduce is actually a fold-left, so the first item in the original list, becomes the inner-most (or last) item in the result list. This could be handled with reverse:
(reduce (fn[a b](cons b a)) '() (reverse '(1 2 3)))
=> (1 2 3)
You can read more about why clojure 'lacks' foldr in here
I'm not that familiar with Racket, but Clojure's reduce appears to differ from Racket's foldr in two major ways:
reduce processes the list from head to tail (vs. tail to head for foldr). In this respect, reduce is similar to foldl.
reduce passes the accumulated value as the first argument to the reducing function (vs. the last argument for foldr/foldl).
The second difference is the reason for the error when using cons -- (cons '() 1) is the first call made, and 1 obviously isn't a list.
If we consider that (conj xs x) is equivalent to (cons x xs) when xs is a list, then (reduce conj '() '(1 2 3)) is equivalent to (cons 3 (cons 2 (cons 1 '()))) which might be more apparent when written as
(->> '()
(cons 1)
(cons 2)
(cons 3))
Now, if you don't mind the result being a vector instead of a list, you could do:
(reduce conj [] '(1 2 3))
Or, if you prefer, you could convert the result into a seq so that it essentially behaves like a list:
(seq (reduce conj [] '(1 2 3)))
Alternatively, you could reverse the input list:
(reduce conj () (reverse '(1 2 3)))
Here is my solution. I don't know how efficient it. We used this kind of solutions in University during Racket lessons.
(reduce #(concat %1 (list %2)) '() '(1 2 3))
=> (1 2 3)
So when given two lists, how do I remove elements in one list from another using only map, filter or foldr? I can't use explicit recursion or lambda either.
The lists consist of only numbers that are sorted in ascending order.
For example, if given (list 1 2 3) and (list 1 3 5), I want to remove all of the second list's elements from the first list. The output I want is (list 2).
If given (list 4 5 6) and (list 2 3 5), I would get (list 4 6).
I'm guessing the final code would be something like:
(define (fn-name list-one list-two)
(filter ... list-one))
Thanks!
Given that you're using Racket, we can write a simple solution in terms of some of the built-in abstract list functions and without using explicit lambdas, we only need a little help from SRFI-26. Try this:
(require srfi/26)
(define (difference lst1 lst2)
(filter-not (cut member <> lst2) lst1))
It works as expected:
(difference (list 1 2 3) (list 1 3 5))
=> '(2)
(difference (list 4 5 6) (list 2 3 5))
=> '(4 6)
You use filter, but you have to curry and invert member so you cannot do it without lambda.
(define (remove-elements needles haystack)
(filter (lambda (x) (not (member ...)))
haystack))
(define (remove-elements needles haystack)
(define (not-in-needles x)
(not (member ...)))
(filter not-in-needles haystack))
Both of these use lambda twice! Once for the define of remove-elements and once explicit / in not-in-needles. In your own example you use lambda once too since (define (name . args) . body) is the same as (define name (lambda args . body))
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))))))
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.
what's the typical way to add an item to the end of the list?
I have a list (1 2 3) and want to add 4 to it (where 4 is the result of an evaluation (+ 2 2))
(setf nlist '(1 2 3))
(append nlist (+ 2 2))
This says that append expects a list, not a number. How would I accomplish this?
You could use append, but beware that it can lead to bad performance if used in a loop or on very long lists.
(append '(1 2 3) (list (+ 2 2)))
If performance is important, the usual idiom is building lists by prepending (using cons), then reverse (or nreverse).
If the "cons at the front, finish by reversing" idiom isn't suitable for you (if you. for example, need to pass the list on to other functions DURING its construction), there's also the "keep track of the end" trick. However, it's probably cleaner to just build the list by consing to the front of it, then finish by using reverse or nreverse before finally using it.
In essence, this allows you to have the list in the right order while building it, at the expense of needing to keep track of it.
(defun track-tail (count)
(let* ((list (cons 0 nil))
(tail list))
(loop for n from 1 below count
do (progn
(setf (cdr tail) (cons n nil))
(setf tail (cdr tail))
(format t "With n == ~d, the list is ~a~%" n list)))
list))
This gives the following output:
CL-USER> (track-tail 5)
With n == 1, the list is (0 1)
With n == 2, the list is (0 1 2)
With n == 3, the list is (0 1 2 3)
With n == 4, the list is (0 1 2 3 4)
(0 1 2 3 4)
You can also use nconc to create the list, which is like append, only it modifies the structure of the input lists.
(nconc nlist (list (+ 2 2)))
You haven't specified the kind of Lisp, so if you use Emacs Lisp and dash list manipulation library, it has a function -snoc that returns a new list with the element added to the end. The name is reversed "cons".
(-snoc '(1 2) 3) ; (1 2 3)
This function might be useful in some situations, it transparently appends a single element to a list, i.e. it modifies the list but returns the appended element (enclosed in a list):
(defun attach1 (lst x)
(setf (cdr (last lst)) (cons x nil)))
;; (attach1 nlist (+ 2 2)) ; append without wrapping element to be added in a list
(append l (list e)) ; e is the element that you want to add at the tail of a list
Cons-ing at the end of a list can be achieved with this function:
(defun cons-last (lst x)
(let ((y (copy-list lst))) (setf (cdr (last y)) (cons x nil)) y))
;; (cons-last nlist (+ 2 2))
If you are trying to add two lists for example (1 2 3) + (1 2 3) here is the code (recursive)
(defun add-to-all (x y)
(T (appendl (+ (first x) (first y)) (add-to-all (tail x) (tail y)) ))
)
If you are trying to add an item to the end of the second list, for example 3 + (1 2 3)
(defun add-to-all (x y)
(cond ((null? y) nil)
(T (appendl (+ (first x) (first y)) (add-to-all (tail x) (tail y)) ))
)
)
If you want to add an item onto the end of a given list without changing that list, then as previously suggested you can use a function like
(defun annex (lst item)
"Returns a new list with item added onto the end of the given list."
(nconc (copy-list lst) (list item)))
This returns a new extended list, while preserving the input list. However, if you want to modify the input list to include the added item, then you can use a macro like
(define-modify-macro pushend (item)
(lambda (place item)
(nconc place (list item)))
"Push item onto end of a list: (pushend place item).")
Pushend operates like push, but "pushes" the item onto the end of the given list. Also note the argument order is the reverse of push.