Riley Wood
Riley Wood

Reputation: 1

How can i write a function which extracts the nth element of a list?

As part of my assignment i have been given the task to:

Write a function that takes two lists as input, a list L1 containing characters and a list L2 containing numbers. For each of the number n contained in L2, the function will display the first n character of the list L1. For example: L1 '("h" "e" "l" "l" "o" "w" "o" "r" "l" "d") L2 '(2 3 1 5 10) Output: h e
h e l
h
h e l l o
h e l l o w o r l d.

i know the function takes two arguments but i don't know how to apply the second the list which is like a selector,it reads each number in the second list and extracts the character in that position in the first list.

( define two-sequences
( lambda ( l1 l2 )
(for/list ([ i l1 ] [ j l2 ])

which function should i use to do this.

Upvotes: 0

Views: 440

Answers (3)

mnemenaut
mnemenaut

Reputation: 820

Write a function that takes two lists as input, a list L1 containing characters and a list L2 containing numbers. For each of the number n contained in L2, the function will display the first n character of the list L1.

The required function can be written compactly using for/list, but when learning Scheme/Racket it can be helpful to build it with basic Scheme functions, without needing to know all the for/xxxx variations and options.

The problem can be split into two parts: (1) produce the characters to display (2) display them as shown in the question.
This answer will show the development of (1) using a systematic design method which can be applied to many problems like this.

(1) Start (in DrRacket) with the example data and a require for testing:

#lang racket
(require test-engine/racket-tests)

(define L1 '("h" "e" "l" "l" "o" "w" "o" "r" "l" "d"))
(define L2 '(2 3 1 5 10))

(test)

(2) Add a stub with signature and purpose, and a minimal example

#lang racket
(require test-engine/racket-tests)

(define L1 '("h" "e" "l" "l" "o" "w" "o" "r" "l" "d"))
(define L2 '(2 3 1 5 10))
                                                          ; *stub* ;; *signature*
(define (take-multiple los lon) ;; ListOfString ListOfNatural -> (ListOf ListOfString)
  ;; produce, for each n in lon, first n elements of los  ; *purpose statement*
  '() )                                                   ; *stub body* (valid result)
                                                          ;
(check-expect  (take-multiple L1 '())  '() )              ; *minimal example*

(test)

(3) Run: note that the test passes ("run early and often": make all tests pass)

(the function is named take-multiple because it "take"s initial elements from los multiple times, according to the numbers in lon)

(4) Identify a template and inventory relevant to the requirement

take-multiple processes a list, so try the commonest template for that kind of argument, "natural recursion":

(define (fn lox) ;; ListOfX -> Y                  ; *template*: (for fn with list argument)
  ;; produce a Y from lox using natural recursion ;
  (cond                                           ;
    [(empty? lox) ... ]                           ; (...  = "base case value" ;; Y )
    [else (....                                   ; (.... = "inventory fn(s)" ;; X Y -> Y )
           (first lox) (fn (rest lox))) ]))       ;
                                                  ; *inventory fns*:
(take lox n) ;; ListOfX Natural -> ListOfX        ; (included because "...first n elements of los")
(cons x lox) ;; X ListOfX -> ListOfX              ; (included because required result is ListOf...)

(5) Edit the template by replacing the generic identifiers appropriately:

(define (take-multiple los lon) ;; ListOfString ListOfNatural -> (ListOf ListOfString)
  ;; produce, for each n in lon, first n elements of los
  (cond
    [(empty? lon) '() ]                           ; '() deduced from above check-expect
    [else (....
           (first lon) (take-multiple los (rest lon))) ]))

This won't run, because we don't know what to replace .... with: to work this out

(6) Add the next simplest example:

(check-expect (take-multiple L1 '(2)) '( ("h" "e") ) )

So we require (.... 2 (take-multiple L1 '())) => '( ("h" "e") ) )
We can see that (take-multiple L1 '()) is '(), and ("h" "e") is (take L1 2)
so (.... (first lon) is (cons (take los (first lon)):

(7) Complete the code and add another example to check:

(define (take-multiple los lon) ;; ListOfString ListOfNatural -> (ListOf ListOfString)
  ;; produce, for each n in lon, first n elements of los
  (cond
    [(empty? lon) '() ]
    [else (cons (take los (first lon)) (take-multiple los (rest lon))) ]))

(check-expect (take-multiple L1 '(2 3)) '( ("h" "e") ("h" "e" "l") ) )

The first function is now complete (run (take-multiple L1 L2) to check).

To produce the required display format, use this function:

(define (display-elements lolox) ;; (ListOf (ListOfX)) ->
  ;; display elements of lolox with newlines between first level lists
  (for-each (lambda (lox)
              (for-each (lambda (x)
                          (display x) (display " "))
                        lox)
              (newline))
            lolox))

So (display-elements (take-multiple L1 L2)) displays:

h e 
h e l 
h 
h e l l o 
h e l l o w o r l d 
> 

Upvotes: 0

Gwang-Jin Kim
Gwang-Jin Kim

Reputation: 10010

In Common Lisp or emacs lisp this function you want is called elt which gives the nth element of a list. - In Racket, you have to define it yourself:

(define (elt l n)
  (cond ((empty? l) '())
        ((zero? n) (car l))
        (else (elt (cdr l) (- n 1)))))
    
(elt '(a b c d e f) 3) ;;=> 'd

In every-day racket, however, one wouldn't use lists - which one has to traverse like this - but vectors - whose access via an index is direct and thus much more faster.

(vector-ref #("a" "b" "c" "d" "e" "f") 3) ;;=> "d"

#(...) is equal to (vector ...) and creates a vector out of the sequence.

Upvotes: 0

ignis volens
ignis volens

Reputation: 9282

You need to print the first n elements of a list. Here's how you do that:

To print the first n elements of a list, lst:

  • if n is zero print a newline;
  • if n is 1 print the first element of lst and a newline;
  • if n is more than 1 print the first element of the lst, a space, and then print n - 1 elements of the rest of lst (hint: you can use a function you are currently writing to do this);
  • if n is anything else then this is an error.

Write this as a proceducre: call it print-n for instance. Then the procedure which answers the question is:

(define (print-ns l ns)
  (for ([n (in-list ns)])
    (print-n l n)))

And

> (print-ns '("h" "e" "l" "l" "o" "w" "o" "r" "l" "d") '(2 3 1 5 10))
h e
h e l
h
h e l l o
h e l l o w o r l d

Upvotes: 0

Related Questions