I have a doubt, I'm using Racket, and I wanna count the digits of a list, but I can't. I try with length but it doesn't work as I want because
(countDigits '(4 5 6 78)) > 5
the answer has to be 5 but, i don't know how to, i have a code for count digits in a number but I don't knowhow to do it in a list.
¿How could I do it?
Here's a possible solution:
(define (countDigits lst)
(apply +
(map (compose string-length number->string)
lst)))
Explanation:
For each number in the list, we convert it to a string
Then, we obtain the length of each string - that will tell us the number of digits
Finally, we add together all the lengths
For example:
(countDigits '(4 5 6 78))
=> 5
A more naive example that wouldn't make your professor look twice :)
Regular Recursion:
(define (countDigits list-of-digits)
(cond [(empty? list-of-digits) 0]
[else (+ 1 (countDigits (rest list-of-digits)))]))
Tail Recursion:
(define (countDigits list-of-digits sum)
(cond [(empty? list-of-digits) sum]
[else (countDigits (rest list-of-digits) (+ 1 sum))]))
Related
I was wondering, if I was given a list such as:
(list 3 6 9 2 1 0 5 9)
and I wanted to produce only the first 5. i.e.: I want to produce:
(list 3 6 9 2 1)
How could I go about doing this. By the way, recursion is not allowed, and the language is intermediate student. Thanks :)
Actually a lis like (1 2 3 4) is a chain of pairs (1 . (2 . (3 . (4 . ())))). You cannot reuse the pairs since you need the 5th pair to point to () (null) instead of the rest of the pair chain. The only way to do this is to make a new pair for each element you'd like by using the same car elements in each.
(define (take lst cnt)
(if (zero? cnt) ; if you ask for zero element
'() ; then return empty list
(cons (car lst) ; else make a pair with first element
(take (cdr lst) ; and result from take with the rest of the list
(- cnt 1))))) ; with one less element than you originally asked for
If memory serves, in addition to car and cdr, Scheme supplies caar, caaar, caaaar and the equivalent repeated ds and the various combinations and permutations. So one solution would be:
(define x (list 3 6 9 2 1 0 5 9))
(list (car x) (cadr x) (caddr x) (cadddr x) (car (cddddr x)))
(and I'm sure that's why you were asked for the first five; there's no cdddddr — the teaching point was likely the permitted repetition of ds and as and the limit to which you can go with those)
I do not know why you would want to do this, but one way to avoid recursion is to unroll the loop:
(define (take1 xs) (cons (car xs) '()))
(define (take2 xs)
(cons (car xs) (take1 (cdr xs))))
(define (take3 xs)
(cons (car xs) (take2 (cdr xs))))
(define (take4 xs)
(cons (car xs) (take3 (cdr xs))))
(define (take5 xs)
(cons (car xs) (take4 (cdr xs))))
Greeting everyone. I'm trying to write an algorithm in Racket but I'm faced with a problem:
I'm studying way of generating different types of grids over surfaces, using a CAD software as a backend for Racket. Basically I have a function that generates a matrix of point coordinates (in the u and v domains) of a parametric surface and another one which connects those points with a line, in a certain order, to create the grid pattern. The problem is, to obtain more complex grids I need to be able to remove certain points from that matrix.
With that said, I have a list of data (points in my case) and I want to remove items from that list based on a true-false-false-true pattern. For example, given the list '(0 1 2 3 4 5 6 7 8 9 10) the algorithm would keep the first element, remove the next two, keep the third and then iterate the same patter for the rest of the list, returning as the final result the list '(0 3 4 7 8).
Any suggestions? Thank you.
Using Racket's for loops:
(define (pattern-filter pat lst)
(reverse
(for/fold ((res null)) ((p (in-cycle pat)) (e (in-list lst)))
(if p (cons e res) res))))
testing
> (pattern-filter '(#t #f #f #t) '(0 1 2 3 4 5 6 7 8 9 10))
'(0 3 4 7 8)
A solution using list functions in SRFI-1:
#!racket
(require srfi/1)
(define (pattern-filter pat lst)
(fold-right (λ (p e acc) (if p (cons e acc) acc))
'()
(apply circular-list pat)
lst))
(pattern-filter '(#t #f #f #t)
'(0 1 2 3 4 5 6 7 8 9 10)) ; ==> '(0 3 4 7 8)
There are other ways but it won't become easier to read.
In Racket I would probably use match to express the specific pattern you described:
#lang racket
(define (f xs)
(match xs
[(list* a _ _ d more) (list* a d (f more))]
[(cons a _) (list a)]
[_ (list)]))
(require rackunit)
;; Your example:
(check-equal? (f '(0 1 2 3 4 5 6 7 8 9 10)) '(0 3 4 7 8))
;; Other tests:
(check-equal? (f '()) '())
(check-equal? (f '(0)) '(0))
(check-equal? (f '(0 1)) '(0))
(check-equal? (f '(0 1 2)) '(0))
(check-equal? (f '(0 1 2 3)) '(0 3))
(check-equal? (f '(0 1 2 3 4)) '(0 3 4))
However I also like (and upvoted) both usepla's and Sylwester's answers because they generalize the pattern.
Update: My original example used (list a _ _ d more ...) and (list a _ ...) match patterns. But that's slow! Instead use (list* a _ _ d more) and (cons a _), respectively. That expands to the sort of fast code you'd write manually with cond and list primitives.
The question is tagged with both scheme and racket, so it's probably not a bad idea to have an implementation that works in Scheme in addition to the versions that work for Racket given in some of the other answers. This uses the same type of approach that's seen in some of those other answers: create an infinite repetition of your boolean pattern and iterate down it and the input list, keeping the elements where your pattern is true.
Here's a method that takes a list of elements and a list of #t and #f, and returns a list of the elements that were at the same position as #t in the pattern. It ends whenever elements or pattern has no more elements.
(define (keep elements pattern)
;; Simple implementation, non-tail recursive
(if (or (null? elements)
(null? pattern))
'()
(let ((tail (keep (cdr elements) (cdr pattern))))
(if (car pattern)
(cons (car elements) tail)
tail))))
(define (keep elements pattern)
;; Tail recursive version with accumulator and final reverse
(let keep ((elements elements)
(pattern pattern)
(result '()))
(if (or (null? elements)
(null? pattern))
(reverse result)
(keep (cdr elements)
(cdr pattern)
(if (car pattern)
(cons (car elements) result)
result)))))
To get an appropriate repeating pattern, we can create a circular list of the form (#t #f #f #t …) we can create a list (#t #f #f #t) and then destructively concatenate it with itself using nconc. (I called it nconc because I've got a Common Lisp background. In Scheme, it's probably more idiomatic to call it append!.)
(define (nconc x y)
(if (null? x) y
(let advance ((tail x))
(cond
((null? (cdr tail))
(set-cdr! tail y)
x)
(else
(advance (cdr tail)))))))
(let ((a (list 1 2 3)))
(nconc a a))
;=> #0=(1 2 3 . #0#)
Thus, we have a solution:
(let ((patt (list #t #f #f #t)))
(keep '(0 1 2 3 4 5 6 7 8 9 0) (nconc patt patt)))
;=> (0 3 4 7 8)
First off, scheme: return a lst that only contains the first element of the lst did not help much, as the question was never really answered, and I followed the contributor's suggestions to no success. Furthermore, I am approaching this with a do loop, and have almost achieved the solution.
I need to make a procedure that will return the first n items in a passed list. For example, (first-n 4 '(5 8 2 9 4 0 8 7)) should give (5 8 2 9).
Here is my approach, the display is there to make sure that the loop is working, which it is:
(define (front-n n list)
(do ((i 0 (+ i 1)))
((> i (- n 1)))
(display (list-ref list i))))
How do I go about making that return a list, or output a list?
Your do-loop, and #Penguino's recursive function, both fail if there are less than n items in the input list. Here is a simple version based on named-let, renamed take which is the normal name for this function:
(define (take n xs)
(let loop ((n n) (xs xs) (zs (list)))
(if (or (zero? n) (null? xs))
(reverse zs)
(loop (- n 1) (cdr xs)
(cons (car xs) zs)))))
Or, if you prefer the recursive function version:
(define (take n xs)
(if (or (zero? n) (null? xs))
(list)
(cons (car xs) (take (- n 1) (cdr xs)))))
The named-let version is preferable to the recursive version, because the recursion isn't in tail position, so it builds a large intermediate stack.
You said that you wanted a version using do. That's harder, because the test that terminates the loop is performed after the action of the loop, and you need to perform the test before the action. You can either test one-ahead, which is awkward, or use this loop that delays the action until after the test has succeeded:
(define (take n xs)
(let ((zs (list)))
(do ((n n (- n 1)) (xs xs (cdr xs)))
((or (zero? n) (null? xs)) (reverse zs))
(set! zs (cons (car xs) zs)))))
The set! isn't particularly Schemely, but at least it shares with the named-let version the property that it doesn't build an intermediate stack.
How about
(define (front-n n list)
(cond ((= 0 n) '())
(else (cons (car list) (front-n (- n 1) (cdr list))))))
with a little pseudo-error-trapping added.
Testing with:
(front-n 4 '(5 8 2 9 4 0 8 7))
(front-n 8 '(5 8 2 9 4 0 8 7))
produces the expected output:
'(5 8 2 9)
'(5 8 2 9 4 0 8 7)
>
Note that the error checking may be useful.
Here is a tail recursive version:
(define (take n a-list)
(define (iter counter result sublist)
(cond
[(empty? sublist) result]
[(< counter n)
(iter
(+ counter 1)
(append result (list (car sublist)))
(cdr sublist))]
[else result]))
(cond
[(= n 0) '()]
[else (iter 0 '() a-list)]))
It differs slightly from the library procedure, because the library procedure throws an error, if you give a take count which is larger than the length of the list, while this function returns the whole list in that case.
Note however, that it makes use of append. I could not figure out a way around that yet.
I'm trying to write a function using Scheme that :
take a list of integers with more than two elements as a parameter
sum the n-th-element and (n+1)-th-element
return this list
Result should be as follows :
> (SumNeighbors (list 1 2 3 4))
(3 5 7)
I think I get the way to add elements but my recursion is totally wrong...
(define (SumNeighbors lst)
(if (not (null? (cdr lst)))
(append (list (+ (car lst) (car (cdr lst)))) (SumNeighbors (cdr lst)))))
Any help would be appreciated.
The solution to this problem follows a well-known pattern. I'll give you some hints, it'll be more fun if you find the answer by your own means:
(define (SumNeighbors lst)
(if <???> ; if there's only one element left
<???> ; we're done, return the empty list
(cons ; otherwise call `cons`
(+ <???> <???>) ; add first and second elements
(SumNeighbors <???>)))) ; and advance recursion
Notice the following:
Your solution is lacking the base case - what happens when the list we're traversing only has one element left? it's time to finish the recursion! and because we're building a list as the output, what should be the value returned?
We normally use cons to build an output list, not append. That's the natural way to build a list
The part of this procedure that falls outside the solution template is the fact that we stop when there's a single elment left in the list, not when the list is empty (as is the usual case)
You'll see that many procedures that iterate over an input list and return a list as output follow the same solution template, it's very important that you learn how and why this works, it's the foundation for writing solutions to other similar problems.
#!r6rs
(import (except (rnrs base) map)
(only (srfi :1) map))
(define (sum-neighbors lst)
(map + lst (cdr lst)))
The higher order function map as defined in SRFI-1 supports uneven lenght arguments. It will stop at the shortest list.
If you call (sum-neighbors '(1 2 3 4)) it will become (map + (1 2 3 4) (2 3 4)) which is the same as (cons (+ 1 2) (cons (+ 2 3) (cons (+ 3 4) '())))
I've been trying to learn some programming on my own by working through the textbook How to Design Programs for Scheme. I've gotten through everything until now. Here's the problem:
9.5.5 Develop the function convert. It consumes a list of digits and
produces the corresponding number. The
first digit is the least significant,
and so on.
Following the first few steps, from data analysis to template, I end
up with this, the bare bones of a program:
;; A list-of-numbers is either 1. an empty list, empty, or 2. (cons n
lon) where n is a number and lon is a list of numbers
;; convert : lon -> number
;; to consume a lon and produce the corresponding number. The least
significant digit corresponds to the first number in the list, and so
on.
;; (= (convert (cons 1 (cons 9 (cons 10 (cons 99 empty))))) 991091)
(define (convert lon)
(cond
[(empty? lon)...]
[(cons? lon)...(first lon)...(convert (rest lon))...]))
How do I get past this stage to, as the book has it, "combining values"?
The one way I think could work is if I multiplied the first value by
10 to the power of the value's significance in the total number, e.g.,
(cons 1 (cons 9 empty)) => 1 * 10^(SIGNIFICANCE), where LEAST
SIGNIFICANCE would be 0. Using my limited understanding of
programming, I figure that requires some counter, where n increases by
one every time the function, in a manner of speaking, is called
recursively. But that looks to me to be an attempt to run two
recursions at the same time. Because expressions are evaluated
sequentially (obviously), you can't call the counter function as you
call the convert function.
So, can anyone help me solve this problem? I would prefer if you
solved this using natural recursion and the CONStructor for lists and
not lambda or other ideas the book hasn't addressed yet.
Thanks!
You don't need to do exponentiation - simple multiplication will do just fine.
(define (convert digits)
(cond
((empty? digits) 0)
(else (+ (* 10 (convert (rest digits))) (first digits)))
)
)
(convert '(1 2 3 4 5 6))
Or, another way of thinking about it:
(define (convert digits)
(convert-helper digits 1 0)
)
(define (convert-helper digits multiplier sofar)
(cond
((empty? digits) sofar)
(else
(convert-helper
(rest digits)
(* 10 multiplier)
(+ (* multiplier (first digits)) sofar)
)
)
)
)
(convert '(1 2 3 4 5 6))
Here's a tail recursive version:
(define (convert lon)
(let rec ((i 0)
(n 0)
(lon lon))
(cond ((empty? lon) n)
(else (rec (+ i 1)
(+ n (* (first lon) (expt 10 i)))
(rest lon))))))