Scheme, Check if anything in two lists are the same - list

Is it possible to check two list against each other if anything is the same in them?
(check-list '(hey cookie monkey) '(apple pizza cookie) ==> #t
I tried something like
(define (check-list list element)
(let ((x list))
(cond ((null? x) #f)
((eq? (car x) (car element)) #t)
(else (check-list (cdr x) element))))
(check-list list (cdr element)))
I know this is not correctly written but don't know how to tackle this problem.
Anyone that can help me?

Sometimes it helps to formulate the process of the solution to a problem in your natural language. Let's simplify the problem a bit.
How do you check if one element is contained in a list? One way to do that would be to compare that one element with each element in the list until you found it - somewhere along the lines you have already done - but not quite. A quick draft would be:
(define (member? e lst)
(cond ((null? lst) #f) ; empty list doesn't contain e
(or (eq? e <??>) ; either the first element is e or
(member? e <??>))) ; the rest of the list contains e
We can use that previous knowledge to solve the real problem at hand. We know how to search for one element in a list, and now we need to search for each element in a list in another list.
(define (check-list lst1 lst2)
(if (or (null? lst1) (null? lst2)) #f ; empty list(s) share no elements
(or (member? <??> <??>) ; first element of lst1 in lst2?
(member? <??> <??>)))) ; rest of lst1 in lst2?
The <??> should be substituded with the appropriate expressions for selecting the parts of the lists.

Similar to a prior answer but exploiting logic primitives:
(define (intersect? list1 list2)
(and (not (null? list1))
(or (member (car list1) list2)
(intersect? (cdr list1) list2))))

If the lists are wicket long you might want to hash the first list and then just iterate through the second. This uses R5RS with srfi-69 and for small lists you'll get a little overhead but
(require srfi/69); alist->hash-table, hash-table-ref/default
(define (intersect? list1 list2)
(let ((hash (alist->hash-table (map (lambda (x) (cons x x)) list2) equal? )))
(let loop ((list list1))
(and (not (null? list))
(or (hash-table-ref/default hash (car list) #f)
(loop (cdr list)))))))

There seems to be a little confusion. The "big" problem here is how to determine if two lists share at least one element in common, let's write a procedure for that called element-in-common?. Before tackling this problem, we need to determine if a single element belongs in one list, that's what check-list should do (notice that in your code check-list receives as a second parameter an element, but you're treating it as if it were a list of elements).
You don't have to write the check-list procedure, it already exists and it's called member. With that knowledge in hand, we can solve the big problem - how to determine if at least one of the elements in one list (let's call it lst1) is in another list (called lst2)?
Simple: we iterate over each of the elements in lst1 using recursion, asking for each one if it belongs in lst2. If just one element of lst1 is a member of lst2, we return #t. If none of the elements in lst1 is in lst2, we return #f. Something like this:
(define (element-in-common? lst1 lst2)
(cond (<???> ; is the first list empty?
<???>) ; then there are no elements in common
((member <???> lst2) ; is the current element of `lst1` in `lst2`?
<???>) ; then there IS an element in common
(else ; otherwise
(element-in-common? <???> lst2)))) ; advance recursion
Don't forget to test your code:
(element-in-common? '(hey cookie monkey) '(apple pizza cookie))
=> #t
(element-in-common? '(hey cookie monkey) '(apple pizza pie))
=> #f

You can use memq to check if first element on the first list is on the second list, and if not then check recursively if something in the rest of the first list is in the second list:
(define (check-list list1 list2)
(cond ((null? list1) #f)
((memq (car list1) list2) #t)
(else (check-list (cdr list1) list2))))

Here's an answer using higher-order functions
in mit-schme
(define (check-list L1 L2)
(apply boolean/or (map (lambda (x) (member? x L2)) L1)))

(define remove-item
(lambda (lst ele)
(if (null? lst)
'()
(if (equal? (car lst) ele)
(remove-item (cdr lst) ele)
(cons (car lst)
(remove-item (cdr lst) ele))))))

Related

SICP/Scheme: Procedure that accepts a list of pairs and an element, returns a list of pairs

I'm having some issues with this problem I've been given. It's not homework, it's actually a problem I've encountered at a test and to deepen my understanding I would like to solve it successfully.
The problem is:
make a procedure element-count that takes a list of pairs "lst" and an element "el" and returns a list of pairs where, if the element "el" exists in "lst" as the first member, then the second member gets increased by 1. Otheriwse we add to the end of "lst" a pair (cons el 1).
The wanted output: element-count '((a 2)) b) -> '((a 2 (b 1))
This is what my code so far looks like:
#lang sicp
(define (append list1 list2)
(if (null? list1)
list2
(cons (car list1) (append (cdr list1) list2))))
(define (count-element lst el)
(cond ((eq? (car lst) el) (+ (cdr lst) 1))
(else (append lst (cons (el 1))))))
The first issue I'm having is that it tells me that "b" is undefined. Obviously, b doesn't need to be defined since I want it in my output. How should I fix this? The environment I'm working in is DrRacket.
The main question is how should I go about defining a list of pairs? Or is my code actually okay? Lists and pairs are still quite confusing to me so I apologize for silly questions.
You are pretty close to the correct solution; I think there is just some confusion about how lists and pairs are defined. Here's an implementation and usage of count-element that does what you want:
(define (count-element lst el)
(cond ((eq? (car lst) el) (+ (cdr lst) 1))
(else (append lst (list (cons el 1))))))
(count-element (list (cons 'a 2)) 'b)
There are two things to note.
First, the way to define a list of pairs is like this:
(list (cons 'a 1) (cons 'c 2))
or
'((a . 1) (c . 2))
Second, this is the correct way to use your append method:
(append lst (list (cons 'b 1)))
or
(append lst '((b . 1)))
That's because append is defined so that you pass in two lists, and it combines them into a single new list. That's why the second parameter is a list containing the pair you want to append.

scheme iteration of summing in lists

i want to ask if someone wants to help me with a iterative scheme code that gives the sum of two lists. I already have the recursive version of the code.
(define (sum-lists l1 l2)(cond ((and (null? l1) (null? l2)) '())
((null? l1) l2)
((null? l2) l1)
(else (cons (+ (car l1) (car l2)) (sum-lists (cdr l1) (cdr l2))))))
The general "iterative procedure" recipe:
Write a helper function that takes an accumulator parameter.
Create each intermediate result in the accumulator.
When you terminate the recursion, return the accumulator.
Pass it a suitable initial accumulator.
It's common when transforming lists to accumulate the result in reverse and then reverse the result when you're done.
A trivial example, incrementing each list element by one:
(define (add-1 ls)
(if (null? ls)
'()
(cons (+ 1 (car ls)) (add-1 (cdr ls)))))
To make it iterative, create a helper function where you cons to the accumulator instead of the recursive result:
(define (add-one ls acc)
(if (null? ls)
(reverse acc)
(add-one (cdr ls) (cons (+ 1 (car ls)) acc))))
(Note that, except for the introduction of acc, the recursion contains the same parts as before but in a different order.)
Then you start it off with an empty accumulator:
(define (add-1 ls)
(add-one ls '()))
Your case has slightly more involved base cases since you need to accomodate inputs of different lengths.
Finishing it left as an exercise.
(Another exercise: figure out why your first condition, (and (null? l1) (null? l2)), is unnecessary.)

Scheme streams and circular lists

In Scheme/Lisp I am trying to make a function that converts a list into a circular list. Therefore, I believe I need to construct an infinite stream in which the tail of the list points to the head of the list.
Here is my code so far:
(define (rotate-list l1 l1copy)
(if (null? (force (cdr l1)))
(cons (car l1) (delay l1copy)))
(cons (car l1) (delay (rotate-list (force (cdr l1)) l1copy))))
All help is greatly appreciated.
No, you don't need streams to make a circular list.
There are two approaches to creating circular lists, the standard Scheme approach, and the Racket approach (since Racket's conses are immutable). I will look at examples using SRFI 1's circular-list function. Here's the reference implementation:
(define (circular-list val1 . vals)
(let ((ans (cons val1 vals)))
(set-cdr! (last-pair ans) ans)
ans))
What that does is to find the last pair in the list of given values, and set-cdr!s it back to the beginning of that list. Pretty straightforward, right?
In Racket, conses are immutable, so set-cdr! does not exist. So instead, Racket does it this way:
(define (circular-list val1 . vals)
(let ([ph (make-placeholder #f)])
(placeholder-set! ph
(cons val1 (let loop ([vals vals])
(if (null? vals)
ph
(cons (car vals) (loop (cdr vals)))))))
(make-reader-graph ph)))
This uses Racket's make-reader-graph function to handle the cycles. Very nifty. :-)

How to get the even elements in a list recursively

I'm trying to create a function that will return the even numbered elements in a list.
For example:
(evens '(a b c d))
should return
(b d)
The code below seems to work for lists that have and odd numbers of elements, but if I give it a list with an even number of elements, it is incorrect.
For example:
(evens '(a b c d e))
will return
(b d)
But:
(evens '(a b c d))
will return
(a c)
Any thoughts?
Changed my code to:
(DEFINE (evens lis)
(cond
((null? lis) '())
(else (cons (cadr lis) (evens (cdr lis))))
))
Gets a error saying that the object passed to safe-car is not a pair?
The problem is that if your list has an even number of elements, the modulo branch is matched and you start consing with the car of the list ... hence in your example, you get the a, and so on.
More importantly, though, you don't need to use length for this function ... and you shouldn't: since length takes linear time in the length of the list, evens now takes quadratic time.
Suggestion: your program should 'remember' whether it's in an 'odd' or 'even' location at each recursive step ... how could you do this (there are several ways)?
Your code has few missing checks and a bit of incorrect logic.
(define (evens lis)
(cond
((null? lis) '())
((eq? (cdr lis) '()) '()) ;missing condition
(else (cons (cadr lis) (evens (cddr lis)))))) ; it is cddr not cdr
I'm going to answer your question with commented examples, in the hope that you actually learn something instead of just being given code that works. Actually, looking at several pieces of code may be more enlightening, assuming that you're new to scheme.
Your original definition looked like this:
(define (evens lis)
(cond (;; Check: Recursion stop condition
(null? lis)
'())
(;; Wrong: Calling length at each step => O(n^2)
;; Wrong: Assuming even element if list has even number of elements
(= (modulo (length lis) 2) 0)
;; Wrong: Recursing with the rest of the list, you'll get odds
(cons (car lis) (evens (cdr lis))))
(else
;; Wrong: Recursing with the rest of the list with cdr, you'll get odds
(evens (cdr lis)))))
Afterwards, you've edited your question to update it to something like this:
(define (evens lis)
(cond (;; Check: Recursion stop condition
(null? lis)
'())
(else
;; Check: Building list with second element
;; Wrong: If lis only has 1 element,
;; (cdr lis) is null and (car (cdr list)) is an error.
(cons (cadr lis)
;; Wrong: Recursing with cdr, you'll get odds
(evens (cdr lis))))))
A solution is to check if the list has at least a second element:
(define (evens lis)
(cond (;; Check: Recursion stop condition 1
(null? lis)
'())
(;; Check: Recursion stop condition 2: list of length = 1
(null? (cdr lis))
'())
(else
;; Check: Building list with second element
;; The previous cond clauses have already sorted out
;; that lis and (cdr lis) are not null.
(cons (cadr lis)
;; Check: Recurse "the rest of the rest" of lis with cddr
(evens (cddr lis)))))
Exercise: Use if and or to simplify this solution to only have 2 branches.
This same question has been asked time and again over the last couple of days. I'll give a direct answer this time, to set it straight:
(define (evens lst)
(if (or (null? lst) ; if the list is empty
(null? (cdr lst))) ; or the list has a single element
'() ; then return the empty list
(cons (cadr lst) ; otherwise `cons` the second element
(evens (cddr lst))))) ; and recursively advance two elements
And here's how to do some error checking first:
(define (find-evens lst)
(if (list? lst)
(evens lst)
(error "USAGE: (find-evens [LIST])")))

Scheme List Derangement (Rearrangement of sorts)

im trying to write a function in Scheme where i accept a list and return all the different derangements (look below for definition) as a list of lists
derangement: A list where no item is in the same place as the original list
ex: '(a b c) -> '(cab)
any help is appreciated!
Compute all of the permutations of the input list and then filter out the ones that have an element in the same position as the input list. If you need more detail, leave a comment.
Edit 1:
Define (or maybe it's defined already? Good exercise, anyway) a procedure called filter that takes as its first argument a procedure p and a list l as its second argument. Return a list containing only the values for which (p l) returns a truthy value.
Define a procedure derangement? that tests if a list l1 is a derangement of l2. This will be handy when paired with filter.
The most obvious solution would be something like this:
(define filtered-permutations
(lambda (lst)
(filter
(lambda (permuted-list)
(deranged? permuted-list lst))
(permute lst))))
Since the number of derangements is considerably lower than then number of permutations, however, this is not very efficient. Here is a solution that mostly avoids generating permutations that are not derangements, but does use filter once, for the sake of simplicity:
(define deranged?
(lambda (lst1 lst2)
(if (null? lst1)
#t
(if (eq? (car lst1) (car lst2))
#f
(deranged? (cdr lst1) (cdr lst2))))))
(define derange
(lambda (lst)
(if (< (length lst) 2)
;; a list of zero or one elements can not be deranged
'()
(permute-helper lst lst))))
(define derange-helper
(lambda (lst template)
(if (= 2 (length lst))
(let ((one (car lst))
(two (cadr lst)))
(filter
(lambda (x)
(deranged? x template))
(list (list one two) (list two one))))
(let ((anchor (car template)))
(let loop ((todo lst)
(done '())
(result '()))
(if (null? todo)
result
(let ((item (car todo)))
(if (eq? item anchor)
;; this permutation would not be a derangement
(loop (cdr todo)
(cons item done)
result)
(let ((permutations
(map
(lambda (x)
(cons item x))
(derange-helper (append (cdr todo) done)
(cdr template)))))
(loop (cdr todo)
(cons item done)
(append result permutations)))))))))))