Counts of repeated elements in a list - list

This program takes a list where elements are repeated, e.g L = (a a a b b b c c c d), and output a list of items and number of repetition e.g ((a 3)(b 3)(c 3) d)
(define counter 0)
(define (compress liste)
(if (or (null? liste) (null? (cdr liste)))
liste
(let ((compressed-cdr (compress (cdr liste))))
(if (equal? (car liste) (car compressed-cdr))
((+ counter 1) compressed-cdr)
((cons (car liste) counter) (= counter 0) (compressed-cdr))))
))
However, I get this error:
Error: application: not a procedure; expected a procedure that can be applied to arguments
given: 1 arguments ...
The error is at the true predicate of the second if condition.

Building the result list in a top-down manner, with the "head-sentinel trick", for simplicity:
(define (rle lst)
(if (null? lst)
'()
(let ((res (list 1))) ; head sentinel
(let loop ((p res) ; result's last cons cell
(elt (car lst))
(cnt 1)
(lst (cdr lst)))
(if (and (not (null? lst))
(equal? elt (car lst)))
(loop p elt (+ cnt 1) (cdr lst))
(begin
(set-cdr! p (list (if (= 1 cnt) elt (list elt cnt))))
(if (null? lst)
(cdr res) ; skip the head in result, on return
(loop (cdr p) (car lst) 1 (cdr lst)))))))))
As #uselpa explained, this is called run-length encoding; for the uniformity of the result I'd suggest using (x 1) representation for non-repeating elements.
And the error "Error: application: not a procedure; expected a procedure", as others have said, means that the system expected to find a procedure but found something else, so can't apply it. Scheme expects to find a procedure as the first form in a list: (proc args ...), and tries to apply it to the arguments. But in your code it is not a procedure, but some other type of data.
If your Scheme has left fold, or reduce, you can run through it twice - first collecting the uniform results, and then applying your special format while reversing (left fold's results are usually built in reversed order):
(define (fold f init lst) ; if fold is not defined,
(reduce f init (cons init lst))) ; define it in terms of reduce
(define (rle lst)
(fold (lambda (x acc) ; NB! MIT-Scheme: (acc x)
(if (= 1 (cadr x)) (cons (car x) acc) (cons x acc)))
'()
(fold (lambda (x acc) ; NB! MIT-Scheme: (acc x)
(if (or (null? acc) (not (equal? (caar acc) x)))
(cons (list x 1) acc)
(cons (list x (+ (cadar acc) 1)) (cdr acc))))
'()
lst)))

As the error message says, the problem is located "at the true predicate of the second if condition":
((+ counter 1) compressed-cdr)
In this case, (+ counter 1) should evaluate to a procedure but it evaluates to a number. I think the problem is that you don't know how to increment the counter.
Your false predicate has the same problem:
((cons (car liste) counter) (= counter 0) (compressed-cdr))))))
where (cons (car liste) counter) yields a list and not a procedure.
I don't think we could really work with this code. I suggest looking at R Sahu's answer, which is close. Alternatively, I can show you a tail-recursive version which you could also have a look at. BTW, this is called run-length encoding, hence I've called my procedure rle:
(define (rle lst)
(define (newres prv cnt res)
(case cnt
((0) res)
((1) (cons prv res))
(else (cons (list prv cnt) res))))
(let loop ((lst lst) (prv null) (cnt 0) (res null))
(if (null? lst)
(if (zero? cnt)
(reverse res)
(loop null null 0 (newres prv cnt res)))
(let ((c (car lst)))
(if (eq? c prv)
(loop (cdr lst) prv (add1 cnt) res)
(loop (cdr lst) c 1 (newres prv cnt res)))))))

It was hard for me to figure out where the problem is in your code. I tried the following that seems to work.
(define (compress liste)
(define (helper in prev out)
(if (null? in)
(list (list (car out) (length out)))
(if (equal? prev (car in))
(helper (cdr in) prev (append out (list (car in))))
(cons (list (car out) (length out)) (compress in)))))
(if (null? liste)
'()
(helper (cdr liste) (car liste) (list (car liste))))
)
It uses helper to gather the output for matching items. When it finds a mismatch, it calls the main function to process the rest of the list. helper simply prepends its results to the results obtained from the main function.
A slightly improved version:
(define (compress liste)
(define (helper in prev out)
(if (null? in)
(list (list prev out))
(if (equal? prev (car in))
(helper (cdr in) prev (+ 1 out))
(cons (list prev out) (compress in)))))
(if (null? liste)
'()
(helper (cdr liste) (car liste) 1))
)
Here's tail-recursive version:
(define (compress liste)
(define (helper-1 in out)
(if (null? in)
'()
(helper-2 (cdr in) (car in) 1 out)))
(define (helper-2 in prev count out)
(if (null? in)
(append out (list (list prev count)))
(if (equal? prev (car in))
(helper-2 (cdr in) prev (+ 1 count) out)
(helper-1 in (append out (list (list prev count)))))))
(helper-1 liste '()))

Related

Replacing a certain number of repeated elements in a list in Racket

I am trying to define the rule 3 of "MIU System" of "Gödel, Escher, Bach" (Douglas Hofstadter), which says:
Replace any III with a U
Example:
MIIIIU → MUIU and MIIIIU → MIUU
Main code:
(define (rule-tree lst)
(if (<= 3 (counter lst #\I))
(append (delete #\I lst) (list #\U))
(append lst empty)))
(define (delete x lst)
(cond [(empty? lst) lst]
[(eq? (first lst) x) (delete x (rest lst))]
[else (append (list (first lst)) (delete x (rest lst)))]))
(define (counter lst target)
(if (empty? lst)
0
(+ (counter (rest lst) target)
(let ((x (first lst)))
(if (list? x)
(counter x target)
(if (eqv? x target) 1 0))))))
With this expression there is no problem:
>(rule-tree '(#\M #\I #\I #\I))
'(#\M #\U)
But I don't know how to determine the position that the "U" should take when finding the 3 "I".
Any suggestion will be very helpful :)
Here is an alternative recursive version, where repl2 encodes the information “we have just encountered one #\I”, while repl3 encodes the information “we have just encountered two #\I”:
(define (repl lst)
(cond ((empty? lst) lst)
((eqv? (first lst) #\I) (repl2 (rest lst)))
(else (cons (first lst) (repl (rest lst))))))
(define (repl2 lst)
(cond ((empty? lst) (list #\I))
((eqv? (first lst) #\I) (repl3 (rest lst)))
(else (cons #\I (cons (first lst) (repl (rest lst)))))))
(define (repl3 lst)
(cond ((empty? lst) (list #\I #\I))
((eqv? (first lst) #\I) (cons #\U (repl (rest lst))))
(else (cons #\I (cons #\I (cons (first lst) (repl (rest lst))))))))
Of course this solution is some kind of hack and cannot scale to a greater number of repetitions. But looking at the structure of this solution and simply generalizing the three functions we can produce a general solution:
(define (repl lst n from to)
(define (helper lst k)
(cond ((empty? lst) (repeat from (- n k)))
((eqv? (first lst) from)
(if (= k 1)
(cons to (helper (rest lst) n))
(helper (rest lst) (- k 1))))
(else (append (repeat from (- n k))
(cons (first lst) (helper (rest lst) n))))))
(define (repeat x n)
(if (= n 0)
'()
(cons x (repeat x (- n 1)))))
We define a function repl that takes a list, the number of copies to replace (n), the element to replace (from) and the element that must be substituted (to). Then we define a helper function to do all the work, and that has as parameters the list to be processed and the number of copies that must be still found (k).
Each time the function encounters a copy it checks if we have finished with the number of copies and substitutes the element, restarting its work, otherwise it decrements the number of copies to find and continues.
If it founds an element different from from it recreates the list with the elements “consumed” until this point (maybe 0) with repeat and then continues its work.
Note that the previous version of the helper function had an error in the final case, when lst is null. Instead of returning simply the empty list, we must return the possibly skipped from elements.

Flatten a non-linear list in lisp [duplicate]

I was reading the book On Lisp by Paul Graham. In Chapter 4, Utility Functions, he gives examples of small functions that operate on lists, which would be helpful while writing a larger program.
One of them is flatten. Given a nested list at any arbitrary level as argument, flatten will remove all the nested elements and put them on the top level.
Below is my attempt at implementing flatten:
(defun flatten (lst)
(labels ((rflatten (lst1 acc)
(dolist (el lst1)
(if (listp el)
(rflatten el acc)
(push el acc)))
acc))
(reverse (rflatten lst nil))))
But the above function does not flatten lists properly.
; returns (1) instead of (1 2)
(print (flatten '(1 (2))))
(1)
Calling the function with (1 (2)) returns (1) instead of (1 2).
I cannot find what's wrong with my implementation of flatten. Is it the way I am using
labels? Or is it the the way I am using the dolist macro? The dolist macro always returns nil. But that should not matter as I am using an accumulator acc to store the flattened list.
push changes the symbol binding in scope. Thus the recursion (rflatten el acc) has it's own acc which is the result there but you don't do anything with the returned result and it doesn't alter the callee acc.
Perhaps a (setf acc (rflatten el acc)) would fix that:
(defun flatten (lst)
(labels ((rflatten (lst1 acc)
(dolist (el lst1)
(if (listp el)
(setf acc (rflatten el acc))
(push el acc)))
acc))
(reverse (rflatten lst nil))))
You're actually very close. As Sylwester mentions, the issue is that (push el acc) only modifies the local binding of el (of which there's a new one for each call to rflatten. As Rainer mentions, it's not really an accumulator in the traditional sense, so I'm going not going to call it acc, but result. Since you're already defining a local function, there's no reason not to define result in a wider scope:
(defun flatten (lst)
(let ((result '()))
(labels ((rflatten (lst1)
(dolist (el lst1)
(if (listp el)
(rflatten el)
(push el result)))))
(rflatten lst)
(nreverse result))))
There are actually a few ways to clean this up, too. The first is a matter of style and taste, but I'd use an &aux variable to bind result, so
(defun flatten (lst &aux (result '()))
...)
The next is that dolist can take a third argument, a form to evaluate as for the return value. This is often used in a "push to create a list, then reverse for the return value" idiom, e.g.,
(let ((result '()))
(dolist (x list (nreverse result))
...
(push ... result)))
You don't want to reverse after every dolist, but you can still return result from the dolist, and thus from rflatten. Then you can simply call nreverse with the result of rflatten:
(defun flatten (lst &aux (result '()))
(labels ((rflatten (lst1)
(dolist (el lst1 result)
(if (listp el)
(rflatten el)
(push el result)))))
(nreverse (rflatten lst))))
A non-recursive code which builds the result by conses, following comments and starting from a code by user:Sylwester:
(defun flatten (lst &optional back acc)
(loop
(cond
((consp lst) (psetq lst (cdr lst) ; parallel assignment
back (cons (car lst) back)))
(back
(if (consp (car back))
(psetq lst (cdar back)
back (cons (caar back) (cdr back)))
(psetq acc (if (car back) (cons (car back) acc) acc)
back (cdr back))))
(t
(return acc))))) ; the result
It's not pretty, but it seems to work. Parallel assignment PSETQ is used to simulate tail-recursive call frame update without worrying about precise sequencing.
Implements the same process as the one encoded nicely by
(defun flatten2 (l z)
(cond
((endp l) z)
((listp (car l)) (flatten2 (car l) (flatten2 (cdr l) z)))
((atom (car l)) (cons (car l) (flatten2 (cdr l) z)))))
(defun flatten (l)
(flatten2 l nil))
with implicit stack operations explicated as list structure manipulations among the variables.
I discovered a solution which does not use helper functions or variable assignment, and constructs the list in a forward manner, which I think is easier to understand.
(defun flatten (lst &aux (re '()))
(cond
((null lst) '())
((listp (car lst))
(append (flatten (car lst))
(append (flatten (cdr lst))
re)))
(t (cons (car lst)
(append (flatten (cdr lst)) re)))))
And we can easily adapt it to control the depth of the flattening!
(defun flatten* (lst depth &aux (re '()))
(cond
((null lst) '())
((listp (car lst))
(append (cond
((= 0 depth) ; flatten none
(list (car lst)))
((< 0 depth) ; flatten down
(flatten* (car lst) (- depth 1)))
((= -1 depth) ; flatten all
(flatten* (car lst) depth))
((< depth -1) ; flatten up
(list (flatten* (car lst) (+ depth 1)))))
(append (flatten* (cdr lst) depth)
re)))
(t (cons (car lst)
(append (flatten* (cdr lst) depth) re)))))

Deleting negated values from a list in Scheme

Resolution takes a list and removes negated elements from that list. The negated form is represented by a list with not in its head. For example if I have '(a (not b) c (not f) (not a) b e) my output should be '(c (not f) e). I have written functions remove-x, which removes an element from the list and match? which takes a value and returns the matching value in the list. If my value is 'a it would return '(not a) from the list.
So my problem is in the resolution function. I want to find if there are any negated elements and if there are, I want to delete both the element and its negation. I also need a way to figure out how to return false if no changes were made to my list:
(define (resolution? alist)
(cond ((null? alist) '())
((not (equal? #f (match? (car alist) (cdr alist))))
(and (remove-x (match? (car alist) (cdr alist)) alist)
(remove-x (car alist) alist)))
(else (cons (car alist) (resolution? cdr alist)))))
These two functions below work:
(define (match? value alist)
(cond ((null? alist) #f)
((and (list? (car alist))
(equal? value (car (cdr (car alist)))))
(car alist))
((equal? value (car alist)) (car alist))
(else (match? value (cdr alist)))))
(define (remove-x x alist)
(cond ((null? alist) '())
((equal? x (car alist)) (cdr alist))
(else (cons (car alist) (remove-x x (cdr alist))))))
I think your solution needs a bit more of work, I'd suggest writing more helper procedures. At the core, the problem to solve is how to find the set difference between two lists. Here's my shot:
; obtain the non-negated variables in the list
(define (vars alist)
(filter (lambda (e) (not (pair? e))) alist))
; obtain the negated variables in the list
(define (negated-vars alist)
(map cadr (filter pair? alist)))
; find the set difference between two lists
(define (difference lst1 lst2)
(cond ((null? lst1) '())
((member (car lst1) lst2)
(difference (cdr lst1) lst2))
(else
(cons (car lst1) (difference (cdr lst1) lst2)))))
; build the resolution, traverse alist and for each member
; check if it's in the corresponding white list of variables
(define (build-resolution alist clean-vars clean-negs)
(cond ((null? alist) alist)
((if (pair? (car alist))
(member (cadar alist) clean-negs)
(member (car alist) clean-vars))
(cons (car alist) (build-resolution (cdr alist) clean-vars clean-negs)))
(else
(build-resolution (cdr alist) clean-vars clean-negs))))
; pre-calculate lists, call the procedure that does the heavy lifting
(define (resolution? alist)
(let* ((vs (vars alist))
(nv (negated-vars alist))
(clean-vars (difference vs nv))
(clean-negs (difference nv vs))
(resp (build-resolution alist clean-vars clean-negs)))
(if (equal? alist resp) #f resp)))
It works as advertised:
(resolution? '(a (not b) c (not f) (not a) b e))
=> '(c (not f) e)
(resolution? '(a (not b) c (not d) (not e) f g))
=> #f
An alternative solution, which could be simplified by the use of fold.
(define resolution?
(lambda (lst)
(let loop ((todo lst)
(result '()))
(if (null? todo)
(alist->list result)
(let ((item (car todo)))
(loop (cdr todo)
(modify-alist result item)))))))
(define modify-alist
(lambda (alist item)
(let ((key (if (symbol? item) item (cadr item)))
(value (if (symbol? item) 'affirmed 'negated)))
(let loop ((todo alist)
(result '()))
(if (null? todo)
(cons (cons key value) result)
(let ((item (car todo)))
(if (eq? key (car item))
(let* ((old-value (cdr item))
(new-value (cond ((eq? value old-value) value)
((eq? 'cancelled old-value) old-value)
(else 'cancelled))))
(cons (cons key new-value)
(append result (cdr todo))))
(loop (cdr todo)
(cons item result)))))))))
(define alist->list
(lambda (lst)
(let loop ((todo lst)
(result '()))
(if (null? todo)
result
(let* ((item (car todo))
(value (cdr item)))
(loop (cdr todo)
(case (cdr item)
((affirmed) (cons (car item) result))
((negated) (cons (list 'not (car item)) result))
(else result))))))))

Using a single function to find min and max numbers in a list without using a driver function?

I am currently confused with the idea behind functional programming in general. I currently have a working solution to my problem (That is, finding the min and max of a list, and returning these in a new list) but to do that, my solution essentially requires 3 functions, and this bothers me, because I am sure there is a way to do it with just 1 function in scheme.
So.. my question is, how do I combine the outputs of 2 functions into 1 concise function? (The driver function)
Here is what I have...
(define (findMax lst) ; Find and return maximum number in a list
(cond [(null? lst) '()]
[(= (length lst) 1) (list-ref lst 0)]
[(> (list-ref lst 0) (list-ref lst (- (length lst) 1))) (findMax (drop-right lst 1))]
[(< (list-ref lst 0) (list-ref lst (- (length lst) 1))) (findMax (cdr lst))]
(else
(findMax (cdr lst))
)
)
)
(define (findMin lst) ; Find and return smallest number in a list
(cond [(null? lst) '()]
[(= (length lst) 1) (list-ref lst 0)]
[(> (list-ref lst 0) (list-ref lst (- (length lst) 1))) (findMin (cdr lst))]
[(< (list-ref lst 0) (list-ref lst (- (length lst) 1))) (findMin (drop-right lst 1))]
(else
(findMin (cdr lst))
)
)
)
I use a driver function to take both of these functions, and make a new list shown here:
(define (findEnds lst)
(list (findMin lst) (findMax lst))
)
So essentially, if given a list:
(6 7 8 4 9 2)
the output would be:
(2 9)
I know there is some way to use lambda possibly to do all of this in 1 function, but I need to be pointed in the right direction. Thanks!
Here's my version (note that I've changed it to return the result as a single dotted pair, rather than a list with two elements†):
(define (min/max lst)
(if (empty? lst)
#f
(let ((next (min/max (cdr lst))))
(define cur (car lst))
(if (not next)
(cons cur cur)
(cons (min (car next) cur) (max (cdr next) cur))))))
Example:
> (min/max '(3 1 4 1 5 9))
(1 . 9)
† If you really want to use a list of two elements, change all the cons to list, and change the (cdr next) to (cadr next).
This is actually a really good challenge that might help with learning some Scheme concepts. I've implemented min/max using fold-left. It might also be fun using a named-let
(define (min/max lst)
(fold-left
(lambda (acc num)
(cons (min num (car acc)) (max num (cdr acc))))
(cons +inf.0 -inf.0)
lst))

How to make pairs from a numeric list based on cardinality?

I have a list '(1 2 1 1 4 5) and want output list as '((1 3)(2 1)(4 1)(5 1)). I have written a small code but I am stuck with how to calculate the cardinality for each number and then put it as pair in list. Can anyone please look at my code and give some ideas?
(define set2bags
(lambda (randlist)
(cond ((null? randlist) '())
(else
(sort randlist)
(makepairs randlist)))))
(define makepairs
(lambda (inlist)
(let ((x 0)) ((newlist '()))
(cond ((zero? (car inlist)) '())
(else
(eq? (car inlist)(car (cdr inlist)))
(+ x 1)
(makepairs (cdr inlist))
(append newlist (cons (car inlist) x)))))))
Your current solution is incorrect - it doesn't even compile. Let's start again from scratch, using a named let for traversing the input list:
(define set2bags
(lambda (randlist)
(cond ((null? randlist) '())
(else (makepairs (sort randlist >))))))
(define makepairs
(lambda (inlist)
(let loop ((lst inlist)
(prv (car inlist))
(num 0)
(acc '()))
(cond ((null? lst)
(cons (list prv num) acc))
((= (car lst) prv)
(loop (cdr lst) prv (add1 num) acc))
(else
(loop (cdr lst) (car lst) 1 (cons (list prv num) acc)))))))
Now it works as expected:
(set2bags '(1 2 1 1 4 5))
=> '((1 3) (2 1) (4 1) (5 1))
The trick is keeping a counter for the cardinality (I called it num), and incrementing it as long as the same previous element (I named it prv) equals the current element. Whenever we find a different element, we add a new pair to the output list (called acc) and reset the previous element and the counter.
Your code is fairly hard to read without proper formating.
I notice a two branch cond, which is easier to read as an if.
In your else clause of set2bags, you call (sort randlist) but leave it as is. You actually want to use this in the next s-expression (makepairs (sort randlist))
So far a pretty good idea.
Now in makepairs you should have better abstraction, say let variables like-first and unlike-first. If the inlist is null, then the function should be the null list, else it's the pair with the car being the list of the car of like-first and the length of like-first and the cdr being the result of calling makepairs on the unlike-first list
(define (makepairs inlist)
(let ((like-first (filter (lambda (x) (equal? x (car inlist)) inlist))
(unlike-first (filter (lambda (x) (not (equal? x (car inlist))) inlist)))
(if (null? inlist)
'()
(cons (list (car inlist) (length like-first)) (makepairs unlike-first)))))
more effecient version
(define (makepairs inlist)
(if (null? inlist)
'()
(let loop ((firsts (list (car inlist)))
(but-firsts (cdr inlist)))
(if (or (null? but-firsts)
(not (equal? (car firsts) (car but-firsts))))
(cons (list (car firsts) (length firsts))
(makepairs but-firsts))
(loop (cons (car but-firsts) firsts) (cdr but-firsts))))))
]=> (makepairs (list 1 1 1 2 4 5))
;Value 17: ((1 3) (2 1) (4 1) (5 1))
If you have your own implementation of sort, say a mergesort you could write this right into the merge part for the best effeciency.
(define (set2bags lst)
(mergesort2bags lst <))
(define (mergesort2bags lst pred)
(let* ((halves (divide-evenly lst))
(first-half (car halves))
(other-half (cadr halves)))
(cond ((null? lst) '())
((null? (cdr lst)) (list (list (car lst) 1)))
(else
(merge-bags
(mergesort2bags first-half pred)
(mergesort2bags other-half pred)
pred)))))
(define (divide-evenly lst)
(let loop
((to-go lst)
(L1 '())
(l2 '()))
(if (null? to-go)
(list L1 L2)
(loop (cdr to-go) (cons (car to-go) L2) L1))))
(define (merge-bags L1 L2 pred)
(cond ((null? L1) L2)
((null? L2) L1)
((pred (caar L1) (caar L2))
(cons (car L1) (merge-bags (cdr L1) L2 pred)))
((equal? (caar L1) (caar L2))
(cons (list (caar L1) (+ (cadar L1) (cadar L2)))
(merge-bags (cdr L1) (cdr L2) pred)))
(else (cons (car L2) (merge-bags L1 (cdr L2) pred)))))
(mergesort2bags (list 1 2 1 1 4 5) <)
;Value 46: ((1 3) (2 1) (4 1) (5 1))
I'm thinking for very large datasets with a lot of repetition this method would pay off.