I'd like to understand the idiomatic way with which to operate over collections of different sizes in clojure. Is there a way I can tell the function 'map' to pad the rest of a collection with some default value?
As an example, suppose I have 3 vectors:
(def x [1 2 3 4])
(def y [1 2 3 4 5])
(def z [1 2 3 4 5 6 7])
(map + x y z) ; yields (3 6 9 12)
In this case, how can I pad x and y with zeroes and have this yield:
(3 6 9 12 10 6 7)
map doesn't do it itself, but you can use a combination of concat and repeat to obtain the desired result:
(def x [1 2 3 4])
(def y [1 2 3 4 5])
(def z [1 2 3 4 5 6 7])
(map +
(concat x (repeat 0))
(concat y (repeat 0))
z) ; => (3 6 9 12 10 6 7)
Here's the API documentation for concat, and for repeat.
And here's a sketch of how you could abstract this away a bit, so you don't need to know which of the collections is longest. (In the snippet above, if you concat all the collections to (repeat 0) you'll have an infinite sequence).
(defn map-longest
[f default & colls]
(lazy-seq
(when (some seq colls)
(cons
(apply f (map #(if (seq %) (first %) default) colls))
(apply map-longest f default (map rest colls))))))
(map-longest +
0
[1 2 3 4]
[1 2 3 4 5]
[1 2 3 4 5 6 7]) ; => (3 6 9 12 10 6 7)
You can see a couple other approaches as answers to this previous question on Stack Overflow.
You can merge vector of maps with variable lengths by the following function:
(defn merge-maps
[& args]
(let [max-count (apply max (map #(count %1) args))
items (map #(take max-count (concat %1 (repeat nil))) args)]
(apply map merge items)))
This function makes the solution more generalized and can take any length of vector of maps.
Related
I am trying to count how many times the first number of the list of list called one, two or three is repeated, the idea of the code that I made is for example to choose the list of list called "one" and then take the first letter that has "a" inside and then compare in this case the first value that would be "10" with the others in this list , in this case I should get it to say that the "10" was repeated once, then it would continue with the other two "b" and "c", but when doing the following code
(define a (list 10 2 3 54 6 9 7 10))
(define b (list 5 1 8 6 5 5 4 77 8 6))
(define c (list 80 80 80))
(define e (list 99 156 54 48 99))
(define d (list 16 94 75 30 56 16 8 16))
(define one (list a b c))
(define two (list c e b a))
(define three (list b c d e))
; receives 'one', 'two' or 'three' and finds how many times the first number of the list is repeated in the list of lists
(define (find-repeated-number list)
(define (find-repeated-number-helper list)
(if (null? list)
0
(if (equal? (car list) (car (cdr list)))
(+ 1 (find-repeated-number-helper (cdr list)))
; displays the number of times the first number of the list is repeated in the list of lists
(find-repeated-number-helper (cdr list)))))
(find-repeated-number-helper list))
(find-repeated-number one)
I get the following error, why is it? how can i get what i want to do? I would appreciate any help
*** ERROR: pair required, but got ()
While loading "./jdoodle.sc" at line 19
Stack Trace:
_______________________________________
0 (car (cdr list))
at "./jdoodle.sc":14
1 (equal? (car list) (car (cdr list)))
at "./jdoodle.sc":14
Command exited with non-zero status 70
I'm still not sure if the main point of this exercise is to write low-level recursive code or use some functions provided by the standard library (in this case, count or a combination of filter and length), but here's my wild guess:
(define a (list 10 2 3 54 6 9 7 10))
(define b (list 5 1 8 6 5 5 4 77 8 6))
(define c (list 80 80 80))
(define e (list 99 156 54 48 99))
(define d (list 16 94 75 30 56 16 8 16))
(define one (list a b c))
(define two (list c e b a))
(define three (list b c d e))
(define (find-count lst element)
(count (lambda (n) (= n element))
lst))
(define (print-count lst)
(let ((number-count (find-count (cdr lst) (car lst))))
(write (string-append
"number of times the first number is repeated: "
(number->string (car lst))
" is "
(number->string number-count)
(if (= number-count 1)
" time"
" times")))
(newline)))
(for-each print-count one)
Output:
"number of times the first number is repeated: 10 is 1 time"
"number of times the first number is repeated: 5 is 2 times"
"number of times the first number is repeated: 80 is 2 times"
I am trying to display a Fibonacci sequence less than an upper bound, but I'm having trouble printing out the series that is constrained by that upper bound.
Without using imperative programming principles with declaring variables such as setf, setq, and set, etc. How can I solve this problem?
So far I have
(defun fibonacci (n &optional (a 0) (b 1))
(if (or (zerop n) (< a n)
nil)
(cons a (fibonacci (1- n) b (+ a b)))))
Expected output of (fibonacci 100): (0 1 1 2 3 5 8 13 21 34 55 89). However, what I am getting is (0 1 1 2 3 5 8 13 21 34 55).
You are decreasing upper bound for no reason. When you remove 1- and move one ) to right place, it works as expected:
(defun fibonacci (n &optional (a 0) (b 1))
(if (or (zerop n) (> a n))
nil
(cons a (fibonacci n b (+ a b)))))
Tests:
CL-USER 4 > (fibonacci 10)
(0 1 1 2 3 5 8)
CL-USER 5 > (fibonacci 100)
(0 1 1 2 3 5 8 13 21 34 55 89)
What you meant is
(defun fibonacci (n &optional (a 0) (b 1))
(if (or (zerop n) (> a n))
nil
(cons a (fibonacci n b (+ a b)))))
You had a ) placement typo / error, and the flipped test. Also, n is the upper limit, not a count. So there's no reason to decrease it.
The task I'm given is, in Racket, to "write a function, countIncreases, which takes a list of numbers and returns how many times the consecutive numbers increase in value. For example, countIncreases '(1 3 2 4 5 1) should return 3 because there are three increases: 1 3, 2 4, 4 5."
I've written a recursive function with the base case being if the list is empty, return 0. I believe my problem is properly comparing one value to the next. Should I be using a standard library list iteration function like foldr or map to accomplish this?
My code and tests are below, and a screenshot of error messages is attached here
(define (countIncreases aList)
(if (empty? aList)
0
(if (< (first aList) (rest aList))
(+ 1 (countIncreases (rest aList)))
(countIncreases (rest aList)))))
(check-expect (countIncreases '(1 3 2 4 5 1)) 3)
(check-expect (countIncreases '()) 0)
(check-expect (countIncreases '(1 2 3 4 5)) 4)
(check-expect (countIncreases '(5 4 3 2 1 2)) 1)
I'm still learning Scheme.
If have these two list of lists:
'((1 2 (3 4) 5) (12 13 4))
'((3 4 9) (7 6 5 4))
I want to get this list:
'((1 2 (3 4) 5) (12 13 4) (3 4 9) (7 6 5 4))
But with cons:
(cons '((1 2 (3 4) 5) (12 13 4)) '((3 4 9) (7 6 5 4)))
I get this list:
'(((1 2 (3 4) 5) (12 13 4)) (3 4 9) (7 6 5 4))
NOTE:
In this example the both lists has two sublists. But they can have n sub-lists.
I have tried with append but it doesn't work when one of the list of lists is only a list:
(append '(1 2 3 4) '((23 24 25 26) (a b c)))
> '(1 2 3 4 (23 24 25 26) (a b c))
Is there a function that do it or do I have to implement it?
The behavior that you want is very specific, you won't find it in the standard library. Good news is, it's simple to implement in a portable and efficient way that covers all the possible cases, assuming that the input lists are non-empty:
(define (my-append lst1 lst2)
(cond ((and (pair? (car lst1)) (pair? (car lst2)))
(append lst1 lst2))
((pair? (car lst1))
(append lst1 (list lst2)))
((pair? (car lst2))
(append (list lst1) lst2))
(else
(append (list lst1) (list lst2)))))
For example:
(my-append '((1 2 (3 4) 5) (12 13 4)) '((3 4 9) (7 6 5 4)))
=> '((1 2 (3 4) 5) (12 13 4) (3 4 9) (7 6 5 4))
(my-append '(1 2 3 4) '((23 24 25 26) (a b c)))
=> '((1 2 3 4) (23 24 25 26) (a b c))
Take integer partition problem for example, I can write the following code to output all partitions of a positive integer n:
(defn foo
([n] (foo n n []))
([n k buf]
(if (zero? n)
(println buf)
(doseq [i (range 1 (inc (min n k)))]
(foo (- n i) i (conj buf i))))))
Then (foo 5) outputs:
[1 1 1 1 1]
[2 1 1 1]
[2 2 1]
[3 1 1]
[3 2]
[4 1]
[5]
The question is how could I write a function bar which generates a lazy-seq containing such results? For example, I want (bar 5) generates ([1 1 1 1 1] [2 1 1 1] [2 2 1] [3 1 1] [3 2] [4 1] [5]).
Here is a roughly equivalent function generating the partitions as a sequence of sequences:
(defn bar
([n] (bar n n))
([n k]
(if (zero? n)
[[]]
(for [i (range 1 (inc (min n k))), tail (bar (- n i) i)]
(cons i tail)))))
For example,
(bar 5)
; ((1 1 1 1 1) (2 1 1 1) (2 2 1) (3 1 1) (3 2) (4 1) (5))
How lazy is bar?
for is lazy.
to make it lazier, wrap the body in a lazy-seq.
I have my doubts about the above.
The function recurses to depth n.
Wrapping the body in lazy-seq I suspect just stacks up lazy
sequences, producing just as deep a recursive call stack on accessing the
first element.
Besides, the same tails are repeatedly computed; the more so since (bar n k) is the same for all k >= n.
If performance of this function is a specific concern, there are iterative algorithms with constant time per step. As #CharlesDuffy's comment implies, these can be re-jigged to produce lazy sequences.
Why gaze into the crystal ball when you can read the book?
The standard namespace clojure.math.combinatorics, hosted here, contains a partition function that produces a lazy sequence of the partitions of any sequence of objects - fast. Integer partition is where we count the elements of each partition of identical objects. They come out in reverse lexicographic order.
For example
(map #(map count %) (combo/partitions (repeat 5 :whatever)))
;((5) (4 1) (3 2) (3 1 1) (2 2 1) (2 1 1 1) (1 1 1 1 1))
No doubt the code can be stripped down to deal with just this case.
Here is recursive solution. There are some ways to optimize it and code is not the best.
(defn partitions [n]
(loop [m n
res [(init-step n m)]]
(let [l (last res)]
(if (= m 1)
res
(if (last-step? (last res))
(recur (- m 1) (vec (conj res (init-step n (- m 1)))))
(recur m (next-step res)))))))
(defn init-step [n m]
(if (= n m)
[n]
(loop [res [m (- n m)]]
(let [l (last res)
f (first res)]
(if (<= l f)
res
(recur (vec (conj (vec (butlast res)) f (- l f)))))))))
(defn next-step [res]
(let [input-vec (last res)
cnt (count input-vec)
i (.indexOf input-vec 1)
j (if (> i -1) (- i 1) (- cnt 1))
m (- cnt j)
new-vec (conj (vec (take j input-vec)) (- (input-vec j) 1))]
(conj res (vec (concat new-vec (repeat m 1))))))
(defn last-step? [input-vec]
(if
(or (nil? input-vec)
(= (count input-vec) 1)
(= (input-vec 1) 1)) true
false))
(partitions 10)
#=> [[10] [9 1] [8 2] [8 1 1] [7 3] [7 2 1] [7 1 1 1] [6 4] [6 3 1] [6 2 1 1] [6 1 1 1 1] [5 5] [5 4 1] [5 3 1 1] [5 2 1 1 1] [5 1 1 1 1 1] [4 4 2] [4 4 1 1] [4 3 1 1 1] [4 2 1 1 1 1] [4 1 1 1 1 1 1] [3 3 3 1] [3 3 2 1 1] [3 3 1 1 1 1] [3 2 1 1 1 1 1] [3 1 1 1 1 1 1 1] [2 2 2 2 2] [2 2 2 2 1 1] [2 2 2 1 1 1 1] [2 2 1 1 1 1 1 1] [2 1 1 1 1 1 1 1 1] [1 1 1 1 1 1 1 1 1 1]]