简体   繁体   中英

Abstract List Functions in Racket/Scheme - Num of element occurrences in list

So I'm currently stuck on a "simple?" function in Racket. It's using the Intermediate Student with lambda language.

Some restrictions on this are that NO recursion is allowed, neither are local functions. It's plain and simple abstract list functions.

What this function is supposed to do is to take in a list of numbers, and output a list of pairs in which each pair has the first element as the number with the second element being the number it has occurred in the list.

Examples:

   (1 1 2 3) => ((1 2) (2 1) (3 1))
   (2 3 4 3) => ((2 1) (3 2) (4 1))

I have a function that produces the number of occurrences by inputting a list of numbers and a number which is:

(define (occurrences lon n)
    (length (filter (lambda (x) (= x n)) lon)))

My approach, which was clearly wrong was:

(define (num-pairs-occurrences lon)
    (list (lambda (x) (map (occurrences lon x) (remove x lon)) x))

I thought the above would work, but apparently my lambda isn't placed properly. Any ideas?

It's a bit trickier than you imagine. As you've probably noticed, we must remove duplicate elements in the output list. For this, is better that we define a remove-duplicates helper function (also using abstract list functions) - in fact, this is so common that is a built-in function in Racket, but not available in your current language settings:

(define (remove-duplicates lst)
  (foldr (lambda (e acc)
           (if (member e acc)
               acc
               (cons e acc)))
         '()
         lst))

Now it's easy to compose the solution using abstract list functions:

(define (num-pairs-occurrences lon)
  (map (lambda (e) (list e (occurrences lon e)))
       (remove-duplicates lon)))

The above might return and output list in a different order, but that's all right. And before you ask: yes, we do need that helper function. Please don't ask for a solution without it...

An easy, self-contained solution would be:

(define (num-pairs-occurences lst)
  (foldl (lambda (e r) 
           (if (or (null? r) (not (= (caar r) e)))
               (cons (list e 1) r)
               (cons (list e (add1 (cadar r))) (cdr r))))
         null
         (sort lst >)))

Basically, you sort the list first, and then you fold over it. If the element (e) you get is the same as the first element of the result list (r), you increment the count, otherwise you add a new sublist to r.

If you sort by > (descending), you can actually use foldl which is more memory-efficient. If you sort by < (ascending), you need to use foldr which is less efficient.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM