How to make an ascending list in Racket? - list

I merge two lists into one in Racket. Here the code:
(define (merge-tail l1 l2)
(cond
[(empty? l1) l2]
[(empty? l2) l1]
[(cons (car l1) (merge-tail l2 (cdr l1)))]))
The result is correct. For example '(15 8 42) '(24 54 7) --> '(15 24 8 54 42 7).
I want to make the result in ascending order. How can I do that?

Related

How to add two lists' elements together into a single list in Scheme?

I'm working on the basics of Scheme and need to find a way to add two lists' elements together (x1 + x2, y1 + y2, z1 + z2) into one list so it becomes (x3, y3, z3)!
I've figured out that to subtract the two lists' elements I can use the "remove" keyword, and to add list2 elements to list1 I can use "append" is there something similar to add the actual elements together?
Here's what I have so far:
(define (my-vector x y z) (list x y z ))
(define first-vector '(1 2 3))
(define second-vector '(4 5 6))
first-vector
second-vector
(define (get-x1 first-vector)(car first-vector))
(define (get-y1 first-vector)(car (cdr first-vector)))
(define (get-z1 first-vector)(car (cdr (cdr first-vector))))
(define (get-x2 second-vector)(car second-vector))
(define (get-y2 second-vector)(car (cdr second-vector)))
(define (get-z2 second-vector)(car (cdr (cdr second-vector))))
(define (combine-vectors first-vector second-vector)
(if (null? first-vector)
second-vector
(cons (car first-vector)
(combine-vectors (cdr first-vector) second-vector))))
(define combined-vectors (combine-vectors first-vector second-vector))
combined-vectors
(define subtract-vectors (remove '(first-vector) second-vector))
(+ (get-x1 first-vector) (get-x2 second-vector))
(+ (get-y1 first-vector) (get-y2 second-vector))
(+ (get-z1 first-vector) (get-z2 second-vector))
the output is currently
(list 1 2 3)
(list 4 5 6)
(list 1 2 3 4 5 6)
5
7
9
I want 5 7 9 to read (list 5 7 9)! Thanks for any help in advance :)
As mentioned by Alex in the comments, map is your best friend here. Minor comment: you're working with lists, not with vectors:
(define (add-lists l1 l2)
(map + l1 l2))
A long and boring alternative would be to do the same iteration and processing by hand, applying the standard patter for traversing a list and building an output list, with the small modification that we'll do it at the same time over two lists:
(define (add-lists l1 l2)
(if (or (null? l1) (null? l2))
'()
(cons (+ (car l1) (car l2))
(add-lists (cdr l1) (cdr l2)))))
Either way, it works as expected:
(define first-list '(1 2 3))
(define second-list '(4 5 6))
(add-lists first-list second-list)
=> '(5 7 9)

Racket: How to combine two lists pairwise with f

I implemented a function (combine f n l1 l2) that combines two lists pairwise with f and returns a list:
(check-expect (combine string-append "" '("1" "2" "3") '("4" "5" "6")) '("14" "25" "36"))
(check-expect (combine + 0 '(1 2 3) '(4 5 6)) '(5 7 9))
(define (combine f n l1 l2)
(if (empty? l1) '()
(cons (foldr f n (first (zip l1 l2)))
(combine f n (rest l1) (rest l2)))))
It uses the (zip l1 l2) function I implemented previously:
(check-expect (zip '(1 2 3 0) '(4 5 6))'((1 4) (2 5) (3 6)))
(define (zip l1 l2)
(local
[(define (take lst n)
(if (zero? n)
'()
(cons (first lst)
(take (rest lst)(- n 1)))))
(define min-lsts
(min (length l1) (length l2)))]
(foldr (lambda (e1 e2 acc) (cons (list e1 e2) acc)) '() (take l1 min-lsts) (take l2 min-lsts))))
(combine f n l1 l2) works as expected, but is there a way to change it to (combine f l1 l2) that does not expect n but still uses foldr?
Thanks in advance!
As long as you always have two arguments you can replace the recursion with foldr and just use the two arguments directly:
(define (combine f l1 l2)
(foldr (lambda (a1 a2 acc)
(cons (f a1 a2)
acc))
'()
l1
l2))
Also zip is implemented overly complicated. It can be done far simpler:
(define (zip l1 l2)
(map list l1 l2))

Add or remove element in the middle of list (Scheme)

Is it possible to add or remove elements in the middle of a linked list in Scheme? I can't seem to think of a way doing this with car/cdr/cons, but I reccon there must be a way to this.
If I have a list '(1 3 5 6), and I need to put in 4 between 5 and 6 for example, is this doable?
Adding an element at a given position was done in a previous answer. Removing an element at a given position is similar:
(define (delete-at k lst)
(cond ((null? lst)
'())
((zero? k)
(cdr lst))
(else
(cons (car lst)
(delete-at (sub1 k) (cdr lst))))))
Here are two versions:
; list-insert : value index list -> list
; return list where the ith element is x
(define (list-insert x i xs)
(if (= i 0)
(cons x xs)
(cons (first xs) (list-insert x (- i 1) (rest xs)))))
(define (list-insert/version2 x i xs)
(define-values (before after) (split-at xs i))
(append before (list x) after))
(list-insert/version2 'x 2 '(a b c d))
(list-insert 'x 2 '(a b c d))
Both versions will allocate a new list. For large lists it will become inefficient.

Sorting a list of pairs based on the second element in Scheme

Can someone give me some advice as to how to go about writing code to sort a list of pairs in increasing order based on the second element of each of the pairs? I don't have an example for you, but this seems like a simple thing to imagine.
Let's try to write a mergesort.
(define (mgsort ls cmp)
(cond
((or (null? ls) (null? (cdr ls)))
ls)
; right? ... then,
(else
(split ls '() '() cmp))))
The most basic tool in dealing with lists is structural recursion:
(define (split ls a b cmp)
(cond
((null? ls)
(merge (mgsort a cmp) (mgsort b cmp) cmp))
(else
(split (cdr ls) b (cons (car ls) a) cmp))))
What's left now it just to write merge – a function that will merge, like "zipping", its two arguments which are sorted lists, so the result is a sorted list too.
(define (merge a b cmp)
(cond
((null? a) b)
((null? b) ....)
((cmp (car a) (car b)) ; right?
(cons
... ;; what? ... with what??
(merge (cdr a) ......)))
(else
(cons
...
(merge a ......)))))
Testing:
(mgsort (list 3 1 5 4 6 2 3) <)
;Value 12: (1 2 3 3 4 5 6)
(mgsort (list (cons 3 1) (cons 4 5) (cons 6 2)) (lambda(a b) (< (cdr a) (cdr b))))
;Value 13: ((3 . 1) (6 . 2) (4 . 5))
cf. how would one merge two strings that are ordered alphabetically in lisp using recursion for an efficient top-down merge function (though in Common Lisp, and nominally for strings, but it really works with lists inside), a by-hand implementation of tail recursion modulo cons optimization technique.

Scheme: merge and sort functions

I'm trying to write a function that merges and then sorts a list, but now I have two different functions; one that merges it and one that sorts it. So I'm trying to write another function, that calls either functions, so it can merge and sort a list at once in that function.
This is what I have:
;; this merges the list
(define (merge l1 l2)
(cond ((null? l1) l2)
((null? l2) l1)
((< (car l1) (car l2)) (cons (car l1) (merge (cdr l1) l2)))
(else (cons (car l2) (merge l1 (cdr l2))))))
;; this sorts the list
(define sort
(lambda (lst)
(if (null? lst)
'()
(insert (car lst)
(sort (cdr lst))))))
(define insert
(lambda (elt sorted-lst)
(if (null? sorted-lst)
(list elt)
(if (<= elt (car sorted-lst))
(cons elt sorted-lst)
(cons (car sorted-lst)
(insert elt (cdr sorted-lst)))))))
You define your merge-sort like this:
(define (merge-sort l1 l2) (sort (merge l1 l2)))
Example:
> (merge-sort (list 8 3 7 4 9 2) (list 5 1 0 6 4))
(0 1 2 3 4 4 5 6 7 8 9)
Why not use one already written for you :)