I'm trying to sort the elements of the following list by using the third element of each sublist:
((v 1 a) (v 3 d) (v 6 b) (v 2 c))
So the result should be:
((v 1 a) (v 6 b) (v 2 c) (v 3 d))
I've tried something like this:
(sort (copy-seq my-list) #'> :key (lambda (x) (third (car x))) )
but it doesn't really work and I'm not sure how should I do this.
CL-USER 15 > (sort (copy-seq '((v 1 a) (v 3 d) (v 6 b) (v 2 c)))
#'string<
:key #'third)
((V 1 A) (V 6 B) (V 2 C) (V 3 D))
Related
Still new to Scheme, and I'm currently having trouble with the creation of a list of pairs constructed from two separate lists of different lengths.
Here is my current code:
#lang racket
(define letters '(a b c))
(define (create-lst-letters lst)
(map (lambda (x y) (list x y)) letters lst))
Console input:
(create-lst-letters '(1 2 3 4 5 6 7 8))
Current output:
map: all lists must have same size
first list length: 8
other list length: 3
Wanted output:
'((a . 1) (b . 2) (c . 3) (a . 4) (b . 5) (c . 6) (a . 7) (b . 8))
Another intuition would be to get the quotient and remainder of the length of the input list divided by "letters". Make a new list by appending "letters" quotient times, and then concatenating the first remainder number of elements of "letters". With that new list perform a map as above. I don't feel this is good practice nor an elegant solution, but I'm out of other ideas.
You can use in-cycle and for/list to concisely produce the output that you want.
#lang racket
(define letters '(a b c))
(define (create-lst-letters lst)
(for/list ([x (in-cycle letters)] [y lst])
(cons x y)))
(create-lst-letters '(1 2 3 4 5 6 7 8))
; '((a . 1) (b . 2) (c . 3) (a . 4) (b . 5) (c . 6) (a . 7) (b . 8))
A pure Scheme version:
#!r7rs
(import (scheme base)
(scheme list))
(define create-lst-letters
(let ((letters (circular-list 'a 'b 'c)))
(lambda (lst)
(map cons letters lst))))
(create-lst-letters '(1 2 3 4 5 6 7 8))
; ==> ((a . 1) (b . 2) (c . 3) (a . 4) (b . 5) (c . 6) (a . 7) (b . 8))
I use Racket and it doesn't have a Red edition of R7RS yet, but thsi can easily be rewritten to R6RS using SRFI-1 (same as (scheme list))
#!r6rs
(import (except (rnrs base) map)
(only (srfi :1) map circular-list))
(define create-lst-letters
(let ((letters (circular-list 'a 'b 'c)))
(lambda (lst)
(map cons letters lst))))
(create-lst-letters '(1 2 3 4 5 6 7 8))
; ==> ((a . 1) (b . 2) (c . 3) (a . 4) (b . 5) (c . 6) (a . 7) (b . 8))
And of course if you don't like writing Scheme code you can write almost the same using #lang racket language.
#lang racket
(require srfi/1)
(define create-lst-letters
(let ((letters (circular-list 'a 'b 'c)))
(lambda (lst)
(map cons letters lst))))
(create-lst-letters '(1 2 3 4 5 6 7 8))
; ==> ((a . 1) (b . 2) (c . 3) (a . 4) (b . 5) (c . 6) (a . 7) (b . 8))
I'm trying to sort a list of polynomials written in this format:
(M [coefficient] [total degree] [Variable List]).
example:
((M 1 1 ((V 1 A))) (M 1 2 ((V 1 A) (V 1 C))) (M 1 2 ((V 2 A))) (M 1 2 ((V 1 A) (V 1 B))))
This is: a + a * c + a ^ 2 + a * b, I need to get a + a * b + c + a * a ^ 2, because a * b < a ^ 2 and a < a ^ 2.
I tried to use the function sort, but my output is:
((M 1 1 ((V 1 A))) (M 1 2 ((V 2 A))) (M 1 2 ((V 1 A) (V 1 B))) (M 1 2 ((V 1 A) (V 1 C))))
that is a + a ^ 2 + a * b + a * c.
I use:
(defun sort-poly (a b)
(cond
(t (sort-poly-helper (varpowers a) (varpowers b)))))
(defun sort-poly-helper (a b)
(cond
((null a) (not (null b)))
((null b) nil)
((equal (third(first a)) (third(first b))) (sort-poly-helper (rest a) (rest b)))
(t (sort (list (third(first a)) (third(first b))) #'string-lessp))))
with:
(sort '((M 1 1 ((V 1 A))) (M 1 2 ((V 1 A) (V 1 C))) (M 1 2 ((V 2 A))) (M 1 2 ((V 1 A) (V 1 B)))) #'sort-poly)
Some help?
Thanks
Your definition of what you want to do is sufficiently opaque that an answer is hard to provide. But the way to start is to stop programming like it is 1956 and use some abstraction.
First of all, let's define how to make a variable and get at its bits:
(defun make-variable (name &optional (degree 1))
`(v ,name ,degree))
(defun variable-name (v)
(second v))
(defun variable-degree (v)
(third v))
Now let's define how to make polynomials from lists of variables. Note that the total degree of the polynomial is computable from the degrees of all the variables, so we do that.
(defun make-polynomial (variables &optional (coefficient 1))
;; The total degree of the polynomial can just be computed from the
;; degrees of its variables
`(m ,coefficient ,(reduce #'* variables :key #'variable-degree)
,variables))
(defun polynomial-coefficient (p)
(second p))
(defun polynomical-total-degree (p)
(third p))
(defun polynomial-variables (p)
(fourth p))
Now, given lists of polynomials, we can sort them using the abstractions we've built: we don't need to grovel around with list accessors (and indeed we could change the representation of polynomials or variables and nothing would ever know).
I am guessing that what you want to sort on is the highest degree of a variable in a polynomial although it is not really clear, and not the total degree of the polynomial (which would be easier). So let's write a function to pull out the highest variable degree:
(defun highest-variable-degree (p)
(reduce #'max (mapcar #'variable-degree (polynomial-variables p))))
And now we can sort lists of polynomials.
CL-USER 23 > (sort (list (make-polynomial (list (make-variable 'a)
(make-variable 'b 2)))
(make-polynomial (list (make-variable 'c)
(make-variable 'd))))
#'<
:key #'highest-variable-degree)
((m 1 1 ((v c 1) (v d 1))) (m 1 2 ((v a 1) (v b 2))))
Remember: it is not 1956 any more.
So for example I have this List : L
((a 1) (b 2) (c 3)) ((d 4) (e 5) (f 6))
how can I turn that into
((a 1) (b 2) (c 3) (d 4) (e 5) (f 6))
A list containing two lists that I need to make one list containing lists.
I know if I car L I get the front half ((a 1) (b 2) (c 3)) and if I cdr L I get the back half
(((d 4) (e 5) (f 6))) but I cant figure out how to turn it into the form
((a 1) (b 2) (c 3) (d 4) (e 5) (f 6))
For "combining" two lists (no matter their contents), use append. And for accessing the first and second elements of a list use (car x) and (cadr x) - which is shorthand for (car (cdr x)). For example:
(define lst '(((a 1) (b 2) (c 3)) ((d 4) (e 5) (f 6))))
(append (car lst) (cadr lst))
=> '((a 1) (b 2) (c 3) (d 4) (e 5) (f 6))
For a more general solution that works with an arbitrary number of sublists, refer to #uselpa's fine answer using apply. Or if you're using Racket, append* will also work for multiple sublists:
(define lst '(((a 1) (b 2) (c 3)) ((d 4) (e 5) (f 6)) ((g 7) (h 8) (i 9))))
(append* lst)
=> '((a 1) (b 2) (c 3) (d 4) (e 5) (f 6) (g 7) (h 8) (i 9))
To complement Oscar's answer, (apply append ...) works for any number of sublists:
(define L '(((a 1) (b 2) (c 3))
((d 4) (e 5) (f 6))))
(apply append L)
=> '((a 1) (b 2) (c 3) (d 4) (e 5) (f 6))
and
(define G '(((a 1) (b 2) (c 3))
((d 4) (e 5) (f 6))
((g 7) (h 8) (i 9))))
(apply append G)
=> '((a 1) (b 2) (c 3) (d 4) (e 5) (f 6) (g 7) (h 8) (i 9))
I need to make a function that transforms 2 list in one in lisp?Can you please help me?
(A B C) (X Y Z) --> ((A.X) (B.Y) (C.Z))
This is the example
For the case you asked :
CL-USER> (mapcar #'cons '(1 2 3) '(a b c))
((1 . A) (2 . B) (3 . C))
If you want to generalize :
CL-USER> (mapcar #'list '(1 2 3) '(a b c) '(x y z))
((1 A X) (2 B Y) (3 C Z))
In a function :
(defun foo (&rest l)
(apply #'mapcar #'list l))
Which gives:
CL-USER> (foo '(1 2 3) '(a b c) '(x y z))
((1 A X) (2 B Y) (3 C Z))
I have a list of functions, a list of elements, and I'd like to apply all the functions on all the elements then append all the resulting lists together. I did it as follow
(defun apply-functions(funcs elements)
(if (null funcs)
nil
(append (mapcar #'(lambda (x) (funcall (car funcs) x)) elements) (apply-functions (rest funcs) elements))))
It works as intended, but I don't like it. Is there a cleaner, more concise way of doing it?. I am new to lisp, and still getting used to the lispish style of doing things.
I don't know if you like loop macro (and I don't want to spoil anyone), but try this:
(defun apply-functions (fs es)
(loop for f in fs appending (mapcar f es)))
This is the same idea as yours, just shorter:
(defun apply-functions (functions elements)
(mapcan #'(lambda (x) (mapcar x elements)) functions))
I would define a function, call-each that returns a new function,
returning the list of calling each function on it's argument:
(defun call-each (fns)
(lambda (arg)
(mapcar (lambda (fn)
(funcall fn arg))
fns)))
(funcall (call-each (list #'third #'second #'first)) '(a b c))
;=> (C B A)
cl has the function mapcan which is basically nconc + mapcar :
(mapcan #'reverse '((a b c)
(e f g)
(h i j)))
;=> (C B A G F E J I H)
(mapcan (call-each (list #'identity #'1+)) '(1 3 5 7 9))
;=> (1 2 3 4 5 6 7 8 9 10)
unfortunately, nconc, which mapcan uses, is destructive:
(let ((data '((a b c)
(d e f)
(g h i))))
;;here be dragons
(list (mapcan #'identity data)
data))
;=> ((A B C D E F G H I) ((A B C D E F G H I) (D E F G H I) (G H I)))
alexandria to the rescue:
(let ((data '((a b c)
(d e f)
(g h i))))
;;safe version
(list (alexandria:mappend #'identity data)
data))
;=> ((A B C D E F G H I) ((A B C) (D E F) (G H I)))
note that using mapcan is more efficient, but unless you know exactly where
your data is coming from, and who owns it, mappend is the way to go.
so you could write:
(defun apply-functions (fs es)
(when fs
(alexandria:mappend (call-each fs) es))
(apply-functions (list #'identity #'1+) '(1 3 5 7 9))
;=> (1 2 3 4 5 6 7 8 9 10)