Clojure - indexing a sequence without using nexts - clojure

New to Clojure and trying to figure out how to index a sequence without using lots of nexts. For instance say I have the sequence:
(a b c d e f g h)
and I want to incorporate into a function the returning of the 4th item of the sequence. There must be some way besides (next (next (next sequence_name)))? So I could just pass the number 4 to the function (or any other number) and get that item from the sequence. Thanks!

A few different ways:
(take 1 (drop 3 '(a b c d e f g h))) ;; d
(nth '(a b c d e f g h) 3) ;; d
(nth [a b c d e f g h] 3) ;; d
(nth (vec '(a b c d e f g h)) 3) ;;d
I recommend you become familiar with the sequence manipulation functions in the Clojure Cheat Sheet - it's totally worth it. Clojure's sequence library is extremely rich.

good old nth should do the trick
user> (nth '(a b c d e f g h) 4)
e
(that is indexed from 0 of course)

Related

Assigning random values to the elements of a list

From this question we can construct an interleaved list out of two lists with a different length (according to Sylwester answer making use of circular-list). My question is how can we do the same but taking the elements of the second list randomly.
That is, I want to assign to the elements of a list a random value out of a list. For example: given the assigning list '(0 1) and whatever list '(a b c d) I want as the output a list such as '((a 0) (b 0) (c 1) (d 0)) or '((a 1) (b 0) (c 0) (d 1)) for example.
My attempts are:
(map cons '(a b c d) (circular-list (random '(0 1))))
which gives '((a . 0) (b . 0) (c . 0) (d . 0)) or '((a . 1) (b . 1) (c . 1) (d . 1)) and nothing different and
(map cons '(a b c d) (list (random '(0 1))))
which gives '((a . 0)) or '((a . 1)) and nothing different.
PS: I am making use of a function called random and defined as
(define (random lst) (list-ref lst (random (length lst))))
which in my example would take randomly 0 or 1 out of a list '(0 1).
To avoid confusion, you should rename your new "random" function on lists to random-element or something similar. That way both people reading your code, and Racket, will know the difference.
random : PositiveNaturalNumber -> NaturalNumber
random-element : [NonEmptyListof X] -> X
These two different functions need to have two different names so that when you want to refer to the first one random from Racket, you can do so. Otherwise Racket (as well as other people reading your code) will think you mean random-element when you really want random.
This confusion matters in the body of your definition of "random":
; /--------------<< This should be renamed to `random-element`
; \/
(define (random lst)
(list-ref lst (random (length lst))))
; /\
; \------<< This is meant to be the original Racket `random`
; but it ends up referring to "random-element" because
; of the naming conflict
Because of this name conflict, when this definition of random is put in a File, and I run a Repl for that File, I get an error like this:
> (random '(A B C D E F G))
length: contract violation
expected: list?
given: 7
When this is renamed, the definition should look like this:
;; random-element : [NonEmptyListof X] -> X
(define (random-element lst)
(list-ref lst (random (length lst))))
; /\
; \-------<< This is the `random` from Racket, not the "new" one
Using it:
> (random-element '(A B C D E F G))
'E
> (random-element '(A B C D E F G))
'B
> (random-element '(A B C D E F G))
'D
> (random-element '(A B C D E F G))
'F
> (random-element '(A B C D E F G))
'C
The comments can't contain code fragments, so ...
What does this program give?
#lang racket
(require srfi/1)
(random '(0) '(1))
On my computer with Racket 7.0 I get:
random: contract violation
expected: exact-integer?
given: '(0)
argument position: 1st
other arguments...:

Lisp program that duplicates an element of a list using a list of integers

I'm working on a program that takes a list of elements and each individual element is duplicated based on an integer contained in a 2nd list of integers. for example if I had a list of
(A B C D)
being duplicated by:
(1 5 4 2)
I would have
(A B B B B B C C C C D D)
So far I have
(defun COPY (X Y)
(if (zerop Y)
nil
(cons S (COPY X (1 - Y)))))
Of course this is only duplicating a single element a single number of times. Does anybody have a good idea how to go about this?
Use mapcan and
make-list (which is the library version of your copy):
(mapcan (lambda (letter num)
(make-list num :initial-element letter))
'(A B C D) '(1 5 4 2))
==> (A B B B B B C C C C D D)
or just
(mapcan #'copy '(A B C D) '(1 5 4 2))
If you are required to use simple recursion, you can also write
(defun copy-list-elements (elements counts)
(and elements counts
(let ((count (pop counts)))
(if (plusp count)
(cons (car elements)
(copy-list-elements elements
(cons (1- count) counts)))
(copy-list-elements (cdr elements)
counts)))))
(copy-list-elements '(A B C D E) '(1 5 4 0 2))
==> (A B B B B B C C C C E E)
Note that the recursive version is longer and probably slower.
Loop over the two lists, call copy, and append the results.
(loop for letter in letters
for count in counts
nconcing (copy letter count))

Recursively remove and replace items in clojure

My problem is removing an item from a list and replacing it with a new value.
For example, if I had the list '(F J (N R D A)), and I wanted to replace it with a brand new list such as '(F J (M G E Q F)). So I would be removing the innermost list and replacing it with a new one. Any advice?
You can use clojure.walk to recursively replace elements of a data structure:
(def my-list '(F J (N R D A)))
(walk/postwalk
#(if (= '(N R D A) %)
'(M G E Q F)
%)
my-list)
=> (F J (M G E Q F))
How about:
(replace {'(N R D A) '(M G E Q F)} '(F J (N R D A))) => (F J (M G E Q F))

applying list of functions to list in common lisp

I have a list of functions, a list of elements, and I'd like to apply all the functions on all the elements then append all the resulting lists together. I did it as follow
(defun apply-functions(funcs elements)
(if (null funcs)
nil
(append (mapcar #'(lambda (x) (funcall (car funcs) x)) elements) (apply-functions (rest funcs) elements))))
It works as intended, but I don't like it. Is there a cleaner, more concise way of doing it?. I am new to lisp, and still getting used to the lispish style of doing things.
I don't know if you like loop macro (and I don't want to spoil anyone), but try this:
(defun apply-functions (fs es)
(loop for f in fs appending (mapcar f es)))
This is the same idea as yours, just shorter:
(defun apply-functions (functions elements)
(mapcan #'(lambda (x) (mapcar x elements)) functions))
I would define a function, call-each that returns a new function,
returning the list of calling each function on it's argument:
(defun call-each (fns)
(lambda (arg)
(mapcar (lambda (fn)
(funcall fn arg))
fns)))
(funcall (call-each (list #'third #'second #'first)) '(a b c))
;=> (C B A)
cl has the function mapcan which is basically nconc + mapcar :
(mapcan #'reverse '((a b c)
(e f g)
(h i j)))
;=> (C B A G F E J I H)
(mapcan (call-each (list #'identity #'1+)) '(1 3 5 7 9))
;=> (1 2 3 4 5 6 7 8 9 10)
unfortunately, nconc, which mapcan uses, is destructive:
(let ((data '((a b c)
(d e f)
(g h i))))
;;here be dragons
(list (mapcan #'identity data)
data))
;=> ((A B C D E F G H I) ((A B C D E F G H I) (D E F G H I) (G H I)))
alexandria to the rescue:
(let ((data '((a b c)
(d e f)
(g h i))))
;;safe version
(list (alexandria:mappend #'identity data)
data))
;=> ((A B C D E F G H I) ((A B C) (D E F) (G H I)))
note that using mapcan is more efficient, but unless you know exactly where
your data is coming from, and who owns it, mappend is the way to go.
so you could write:
(defun apply-functions (fs es)
(when fs
(alexandria:mappend (call-each fs) es))
(apply-functions (list #'identity #'1+) '(1 3 5 7 9))
;=> (1 2 3 4 5 6 7 8 9 10)

Scheme: CAR and CDR of a list

I am confused as to how car and cdr work on lists. Here is an example of what I have tried:
(define sample (read))
(display sample)
(display (car sample))
(display (cdr sample))
(display (car (cadr sample)))
(display (cdr (cdr sample)))
On entering the value '(A B C D E F), here is what I get:
'(a b c d e f)
quote
((a b c d e f))
a
()
I am not able to understand that how quote can be the car of sample. Also, why does (cdr sample) output ((a b c d e f))?
Language: DrScheme - R5RS - Scheme
If you wanted to simply type the list (a b c d e f), you should just type (a b c d e f). What you typed, instead, was (quote (a b c d e f)) because the ' operator is short for (quote ...).
Your list literally has the first element quote and the second element (a b c d e f). Of course, when you're writing source code, you need the quote to prevent the S-expressions from being executed.