In clojure, why doesn't "some" function work consistently on collections? - list

For below, why does the last one return a nil? Function "some" doesn't work on list of lists?
(some #(= % 1) '(1 3) ) ; ==> true
(some #(= % '(1 3)) ['(1 3) '(1 2 3)] ) ; ==> true
(some #(= % '(1 3)) '('(1 3) '(1 2 3)) ) ;==> nil

You should modify the expression like this:
(some #(= % '(1 3)) '((1 3) (1 2 3)) )
=> true
You already quoted the list by using ', you don't need to quote again in the quoted list.
You can easily check what happened in REPL:
user=> '((1 3) (1 2 3))
((1 3) (1 2 3))
user=> '('(1 3) '(1 2 3))
((quote (1 3)) (quote (1 2 3)))

#Kevin
I see #ntalbs answered but I am in the habit of testing various timings. You may be curious to note the time difference I observed:
(time (some #{'(1 3)} '((1 3) (1 2 3)))) ;0.073
(time (some #(= % '(1 3)) '((1 3) (1 2 3)))) ;0.632
(time (nil? (some #{'(1 3)} '((1 3) (1 2 3))))) ;0.068
(time (nil? (some #(= % '(1 3)) '((1 3) (1 2 3))))) ;0.628
If you are processing large amounts of data this may be a useful knowledge

As ntalbs points out, the issue here is double quoting. It may be a better idea to use vectors instead of lists, or build lists with list. Both would save you some confusion and vectors have different performance characteristics (near constant random access time).
(some #(= % '(1 3)) [[1 3] [1 2 3]])
(some #(= % '(1 3)) (list (list 1 3) (list 1 2 3)))

Related

Drop function in clojure

Given the following function, I could not understand what map function is receiving as second parameter.
(def tails
(fn [seq]
(map drop
(range (inc (count seq)))
(repeat (inc (count seq)) seq))))
Given that seq is (list 1 2 3)
The line:
(range (inc (count seq)))
Will produce ((1 2 3) (1 2 3) (1 2 3))
And the line:
(range (inc (count seq)))
Will produce (0 1 2 3)
So, what is receiving the map function as second parameter?
The second parameter is seq repeated as many times as its length + 1, so you can drop 0 to length elements from it.
For '(1 2 3), you get
(map drop '(0 1 2 3) (repeat 4 '( 1 2 3)))
which (when realized) will become the equivalent of
(list (drop 0 '(1 2 3)) (drop 1 '(1 2 3)) (drop 2 '(1 2 3)) (drop 3 '(1 2 3)))
which evaluates to
((1 2 3) (2 3) (3) ())

Function related to partition that includes all elements?

This behavior of Clojure's partition function is not what I need:
user=> (partition 3 (range 3))
((0 1 2))
user=> (partition 3 (range 4))
((0 1 2))
user=> (partition 3 (range 5))
((0 1 2))
user=> (partition 3 (range 6))
((0 1 2) (3 4 5))
I need the 'leftover' portions of the collection to be included, e.g.:
user=> (partition* 3 (range 4))
((0 1 2) (3))
user=> (partition* 3 (range 5))
((0 1 2) (3 4))
Is there a standard library function that does what I want?
You're looking for partition-all. Just replace it in your example:
user> (partition-all 3 (range 4))
((0 1 2) (3))
user> (partition-all 3 (range 5))
((0 1 2) (3 4))
There is a pad argument in the 4-arity version of partition:
user=> (partition 3 3 [] (range 4))
((0 1 2) (3))
user=> (partition 3 3 [] (range 5))
((0 1 2) (3 4))
The docstring:
user=> (doc partition)
-------------------------
clojure.core/partition
([n coll] [n step coll] [n step pad coll])
Returns a lazy sequence of lists of n items each, at offsets step
apart. If step is not supplied, defaults to n, i.e. the partitions
do not overlap. If a pad collection is supplied, use its elements as
necessary to complete last partition upto n items. In case there are
not enough padding elements, return a partition with less than n items.

Expression inside a list in Racket

If I have a list like this (define lst '((,(car '(1 2)) (1 2)) (,(car '(3 4)) (3 4))) ) and I try to 'evaluate' the expression (i.e. take as result '((1 (1 2)) (3 (3 4)))) I obtain the same list that I have.
I know that if I use (quoasiquote ((,(car '(1 2)) (1 2)) (,(car '(3 4)) (3 4))) I obtain what I'm looking for, but the problem is in an execution with an iterative method, where (I think) I'm not capable of take only the values, without being a list. (i.e. take only the second part of the quoasiquote expression).
For example, if I use for/list and I do (list-ref lst 0), I obtain '(,(car '(1 2)) (1 2)), when I want (,(car '(1 2)) (1 2)) for use it in quoasiquote function.
How can I obtain the expression inside a list and evaluate it?
Thank you.
So when you quote data it's like single quotes in some popular Algol dialects like perl. eg print '$_'; actually prints $_ and not the value the variable $_ represents. If you would have used double quotes the variables in the string is expanded to it's value.
In Scheme we have (quote x) which is 'x. Nothing in it will ever going to become evaluated since it's quoted with '. If it were `x, which is the same as (quasiquote x) then Scheme looks for ,expression (same as (unquote expression) ) and ,#expression (same as (unquote-splicing expression) ). These quote forms are NOT procedures but macros. It transforms your static code to different static code.
So (begin (define test 10) `((1 2) (3 ,(+ test 4)))) ; ==> ((1 2) (3 14))
What Scheme really does is transform it into (list '(1 2) (list 3 (+ test 4))), while if it was `((3 ,(+ test 4)) (1 2)) it turns into (cons (list 3 (+ test 4)) '((1 2))) since the tail can be a constant but the head cannot if it needs to have a evaluated tail.
I get the impression from you question that you think you can store the text and expand them later like (let ((x '((1 2) (3 ,(+ test 4))))) `x) but that will not work since quasiquote is a macro and thus it will evaluate to x. and (let ((x '((1 2) (3 ,(+ test 4))))) `,x) would evaluate to ((1 2) (3 ,(+ test 4))).
I'm pretty confident that we have an XY-problem here because what you describe is pretty unusual. Also, the only solution I imagine here is using eval, which again shows that you're probably heading into the wrong direction.
But here's a little attempt at what I believe you want:
(define lst '((list (car '(1 2)) '(1 2))
(list (car '(3 4)) '(3 4))))
(define-namespace-anchor nsa)
(define ns (namespace-anchor->namespace nsa))
(for/list ((i lst))
(define e (eval i ns))
(printf "evaluating ~a to ~a\n" i e)
e)
which will print
evaluating (list (car '(1 2)) '(1 2)) to (1 (1 2))
evaluating (list (car '(3 4)) '(3 4)) to (3 (3 4))
and evaluate to
'((1 (1 2)) (3 (3 4)))

Append a list to a sequence of lists

I have a sequence of lists:
(def s '((1 2) (3 4) (5 6)))
And I want to append another list to the tail of this sequence, i.e.
(concat-list s '(7 8))
=> '((1 2) (3 4) (5 6) (7 8))
Various approaches that (obviously) don't work:
(cons '((1 2)) '(3 4))
=> (((1 2)) 3 4)
(conj '(3 4) '((1 2)))
=> (((1 2)) 3 4)
(concat '((1 2)) '(3 4))
=> ((1 2) 3 4)
;; close, but wrong order...
(conj '((1 2)) '(3 4))
=> ((3 4) (1 2))
;; Note: vectors work - do I really have to convert entire
;; structure from lists to vectors and back again?
(conj [[1 2]] [3 4])
=> [[1 2] [3 4]]
What are some possible implementations of concat-list, or does there exist library function that does this?
If you find this collection is usually growing to the right, then you should start it off as a vector and keep it that way.That will be the most efficient and convenient.
However, if this collection mostly grows to the left and only rarely to the right, concat is probably your best option:
(concat '((1 2)) ['(3 4)])
Note that concat returns a lazy sequence, not a persistent list.
If the collection is large and grows frequently on both ends, you may want a more advanced collection type like a finger tree or a flexvec.
There may be a better solution, but here's one way:
user=> s
((1 2) (3 4) (5 6))
user=> s2
(7 8)
user=> (concat s (cons s2 '()))
((1 2) (3 4) (5 6) (7 8))

How does this function which reverses the interleave process into x number of subsequences

I completed exercise 43 on 4clojure the other day and checked some of the other solutions. One in particular has confused me.
The challenge asks you to write a function which satisfies all of these:
(= (__ [1 2 3 4 5 6] 2) '((1 3 5) (2 4 6)))
(= (__ (range 9) 3) '((0 3 6) (1 4 7) (2 5 8)))
(= (__ (range 10) 5) '((0 5) (1 6) (2 7) (3 8) (4 9)))
My solution was this:
(fn [l n]
(map #(map second %) (vals (group-by #(mod (first %) n)
(map vector (iterate inc 0) l)))))
User himself had this solution:
#(apply map list (partition %2 %1))
and I couldn't work out how it worked.
Let's work through the first problem:
(= (__ [1 2 3 4 5 6] 2) '((1 3 5) (2 4 6)))
well the (#(partition %2 %1) [1 2 3 4 5 6] 2) would give us ((1 2) (3 4) (5 6)) now how does apply map list on that produce (1 3 5) (2 4 6)
apply is using the ((1 2) (3 4) (5 6)) as a variable length list of additional arguments. Then iteration of the map is applying the list function to all three of these additional lists.
As a result it expands as follows:
(apply map list '((1 2) (3 4) (5 6)))
=> (map list '(1 2) '(3 4) '(5 6))
=> (list 1 3 5) and (list 2 4 6)