(def mine '(a b c))
(def yours '(a b))
(remove yours mine)
; should return (c)
I was advised to use remove in another thread but it doesn't work.
Anyone can advise?
Assuming you want to remove from mine every element that also exists in yours, there are a few approaches. You can convert the lists to sets and use difference, like this:
(require '[clojure.set :refer [difference]])
(def mine '(a b c))
(def yours '(a b))
(difference (set mine) (set yours))
;; => #{c}
But this does not preserve the order of elements that remain from mine. If you want to preserve the order, you can instead use remove. To do that, we first define a yours? predicate that will return true for an element iff that element occurs in yours:
(def yours-set (set yours))
(def yours? (partial contains? yours-set))
If our set yours only contains truthy values like that are neither nil nor false, we could define it like (def yours? (set yours)) since a set implements the IFn interface but this approach will not work if yours contains elements such as nil or false as #amalloy pointed out.
(remove yours? mine)
;; => (c)
The above code means that we remove every element from mine for which yours? evaluates to true. Yet another, more verbose approach, is to use the opposite of remove, that is filter, and passing in the opposite of the predicate.
(filter (complement yours?) mine)
;; => (c)
but I see no gain of that more verbose approach here.
If you know that you want a vector as a result, you can instead use into, passing in a removeing transducer as argument.
(into [] (remove yours?) mine)
;; => [c]
contains? is a horrible misnamer in Clojure in my view. (No, it does NOT check, whether an element is contained in a collection! It just checks whether for a key (an index or key) there exist a value in the collection.)
Use some in combination with #{} to check for membership in a collection!
(remove #(some #{%} yours) mine)
;; => (c)
Or:
(defn in? [coll x] (some #{x} coll))
(remove #(in? yours %) mine) ;; => {c}
Related
I need to write a Clojure function which takes an unevaluated arbitrarily deep nesting of lists as input, and then determines if any item in the list (not in function position) is non-numeric. This is my first time writing anything in Clojure so I am a bit confused. Here is my first attempt at making the function:
(defn list-eval
[x]
(for [lst x]
(for [item lst]
(if(integer? item)
(println "")
(println "This list contains a non-numeric value")))))
I tried to use a nested for-loop to iterate through each item in every nested list. Trying to test the function like so:
=> (list-eval (1(2 3("a" 5(3)))))
results in this exception:
ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn listeval.core/eval7976 (form-init4504441070457356195.clj:1)
Does the problem here lie in the code, or in how I call the function and pass an argument? In either case, how can I make this work as intended?
This happens because (1 ..) is treated as calling a function, and 1 is a Long, and not a function. First you should change the nested list to '(1(2 3("a" 5(3)))). Next you can change your function to run recursively:
(defn list-eval
[x]
(if (list? x)
(for [lst x] (list-eval lst))
(if (integer? x)
(println "")
(println "This list contains a non-numeric value"))))
=> (list-eval '(1(2 3("a" 5(3)))))
There is a cool function called tree-seq that does all the hard work for you in traversing the structure. Use it then remove any collections, remove all numbers, and check if there is anything left.
(defn any-non-numbers?
[x]
(->> x
(tree-seq coll? #(if (map? %) (vals %) %))
(remove (some-fn coll? number?))
not-empty
boolean))
Examples:
user=> (any-non-numbers? 1)
false
user=> (any-non-numbers? [1 2])
false
user=> (any-non-numbers? [1 2 "sd"])
true
user=> (any-non-numbers? [1 2 "sd" {:x 1}])
true
user=> (any-non-numbers? [1 2 {:x 1}])
false
user=> (any-non-numbers? [1 2 {:x 1 :y "hello"}])
true
If you want to consider map keys as well, just change (vals %) to (interleave (keys %) (vals %)).
quoting
As others have mentioned, you need to quote a list to keep it from being evaluated as
code. That's the cause of the exception you're seeing.
for and nesting
for will only descend to the nesting depth you tell it to. It is not a for loop,
as you might expect, but a sequence comprehension, like the the python list comprehension.
(for [x xs, y ys] y) will presume that xs is a list of lists and flatten it.
(for [x xs, y ys, z zs] z) Is the same but with an extra level of nesting.
To walk down to any depth, you'd usually use recursion.
(There are ways to do this iteratively, but they're more difficult to wrap your head around.)
side effects
You're doing side effects (printing) inside a lazy sequence. This will work at the repl,
but if you're not using the result anywhere, it won't run and cause great confusion.
It's something every new clojurian bumps into at some point.
(doseq is like for, but for side effects.)
The clojure way is to separate functions that work with values from functions that
"do stuff", like printing to the console of launching missiles, and to keep the
side effecting functions as simple as possible.
putting it all together
Let's make a clear problem statement: Is there a non number anywhere inside an
arbitrarily nested list? If there is, print a message saying that to the console.
In a lot of cases, when you'd use a for loop in other langs reduce is what you want in clojure.
(defn collect-nested-non-numbers
;; If called with one argument, call itself with empty accumulator
;; and that argument.
([form] (collect-nested-non-numbers [] form))
([acc x]
(if (coll? x)
;; If x is a collection, use reduce to call itself on every element.
(reduce collect-nested-non-numbers acc x)
;; Put x into the accumulator if it's a non-number
(if (number? x)
acc
(conj acc x)))))
;; A function that ends in a question mark is (by convention) one that
;; returns a boolean.
(defn only-numbers? [form]
(empty? (collect-nested-non-numbers form)))
;; Our function that does stuff becomes very simple.
;; Which is a good thing, cause it's difficult to test.
(defn warn-on-non-numbers [form]
(when-not (only-numbers? form)
(println "This list contains a non-numeric value")))
And that'll work. There already exists a bunch of things that'll help you walk a nested structure, though, so you don't need to do it manually.
There's the clojure.walk namespace that comes with clojure. It's for when you have
a nested thing and want to transform some parts of it. There's tree-seq which is explained
in another answer. Specter is a library which is
a very powerful mini language for expressing transformations of nested structures.
Then there's my utils library comfy which contains reduce versions of the
functions in clojure.walk, for when you've got a nested thing and want to "reduce" it to a single value.
The nice thing about that is that you can use reduced which is like the imperative break statement, but for reduce. If it finds a non-number it doesn't need to keep going through the whole thing.
(ns foo.core
(:require
[madstap.comfy :as comfy]))
(defn only-numbers? [form]
(comfy/prewalk-reduce
(fn [ret x]
(if (or (coll? x) (number? x))
ret
(reduced false)))
true
form))
Maybe by "any item in the list (not in function position)" you meant this?
(defn only-numbers-in-arg-position? [form]
(comfy/prewalk-reduce
(fn [ret x]
(if (and (list? x) (not (every? (some-fn number? list?) (rest x))))
(reduced false)
ret))
true
form))
Is it possible to remove the let statement / avoid the intermediate 'x' in the following code?:
(let [x (f a)]
(when (pred? x) x))
I bumped into this problem in the following use case:
(let [coll (get-collection-somewhere)]
(when (every? some? coll) ; if the collection doesn't contain nil values
(remove true? coll))) ; remove all true values
So if the collection is free of nil values, only not-true values remain, like numbers, strings, or whatever.
So, I'm looking for something like this:
(defn pass-if-true [x pred?]
(when (pred? x) x))
Assuming that you don't want to define that pass-if-true function, the best you can do is an anonymous function:
(#(when (every? some? %)
(remove true? %))
(get-collection-somewhere))
You could also extract the predicate and transformation into parameters:
(#(when (%1 %3) (%2 %3))
(partial every? some?)
(partial remove true?)
(get-collection-somewhere))
The let form is necessary to prevent your collection-building function from running twice:
(f a) or (get-collection-somewhere)
This is a typical idiom and you are doing it correctly.
Of course, you don't need the let if you already have the collection and are not building inside this expression.
However, you may wish to see when-let:
https://clojuredocs.org/clojure.core/when-let
It can save some keystrokes in some circumstances, but this isn't one of them.
I know at a certain point in my code that a list only has one element so I obtain it with
(first alist)
But I would also like the code to break if the list has more than one elements to alert me of the erroneous condition. What's an idiomatic way to achieve that in Clojure ?
Replace first with an only (or other poetically named) function with a pre-condition where you want to make your assertion:
(defn only [x] {:pre [(nil? (next x))]} (first x))
(only [1])
=> 1
(only [1 2])
=> AssertionError Assert failed: (nil? (next x)) user/only (NO_SOURCE_FILE:1)
This will blow up on a collection with anything other than one element. Works fine on lazy seqs as well.
(defn only
"Gives the sole element of a sequence"
[coll]
(if (seq (rest coll))
(throw (RuntimeException. "should have precisely one item, but had at least 2"))
(if (seq coll)
(first coll)
(throw (RuntimeException. "should have precisely one item, but had 0")))))
I can't immediately think of a nice concise, idiomatic way to do this.
Option 1 is that there isn't one, because this is a bit of an odd situation. If you know there's supposed to be exactly one element, why is it in a list in the first place?
Option 2 is that there is one, and someone will come along and tell off for not seeing it :)
That said, in your situation I'd probably write something like:
(let [[item & rest] alist]
(if (nil? rest)
(throw (IllegalArgumentException. "Expected a single-element list"))
item))
Possibly more simply, you could also just do (count alist) and make sure it had exactly one item. The code above, though, has the nice property that it won't force evaluation beyond the head of the list, but depending on your use case that might not be a concern.
The Tupelo library has this function defined as a core sanity-check, allowing one to "unwrap" scalar values from length-1 vectors/lists and document the intended result. The definition is simplicity itself:
(defn only
"(only coll)
Ensures that a sequence is of length=1, and returns the only value present.
Throws an exception if the length of the sequence is not one.
Note that, for a length-1 sequence S, (first S), (last S) and (only S) are equivalent."
[coll]
(let [coll-seq (seq coll)
num-items (count coll-seq)]
(when-not (= 1 num-items)
(throw (IllegalArgumentException. (str "only: num-items must=1; num-items=" num-items))))
(clojure.core/first coll-seq)))
You can find a similar function in the SuchWow library and other places.
Given a list of names for variables, I want to set those variables to an expression.
I tried this:
(doall (for [x ["a" "b" "c"]] (def (symbol x) 666)))
...but this yields the error
java.lang.Exception: First argument to def must be a Symbol
Can anyone show me the right way to accomplish this, please?
Clojure's "intern" function is for this purpose:
(doseq [x ["a" "b" "c"]]
(intern *ns* (symbol x) 666))
(doall (for [x ["a" "b" "c"]] (eval `(def ~(symbol x) 666))))
In response to your comment:
There are no macros involved here. eval is a function that takes a list and returns the result of executing that list as code. ` and ~ are shortcuts to create a partially-quoted list.
` means the contents of the following lists shall be quoted unless preceded by a ~
~ the following list is a function call that shall be executed, not quoted.
So ``(def ~(symbol x) 666)is the list containing the symboldef, followed by the result of executingsymbol xfollowed by the number of the beast. I could as well have written(eval (list 'def (symbol x) 666))` to achieve the same effect.
Updated to take Stuart Sierra's comment (mentioning clojure.core/intern) into account.
Using eval here is fine, but it may be interesting to know that it is not necessary, regardless of whether the Vars are known to exist already. In fact, if they are known to exist, then I think the alter-var-root solution below is cleaner; if they might not exist, then I wouldn't insist on my alternative proposition being much cleaner, but it seems to make for the shortest code (if we disregard the overhead of three lines for a function definition), so I'll just post it for your consideration.
If the Var is known to exist:
(alter-var-root (resolve (symbol "foo")) (constantly new-value))
So you could do
(dorun
(map #(-> %1 symbol resolve (alter-var-root %2))
["x" "y" "z"]
[value-for-x value-for-y value-for z]))
(If the same value was to be used for all Vars, you could use (repeat value) for the final argument to map or just put it in the anonymous function.)
If the Vars might need to be created, then you can actually write a function to do this (once again, I wouldn't necessarily claim this to be cleaner than eval, but anyway -- just for the interest of it):
(defn create-var
;; I used clojure.lang.Var/intern in the original answer,
;; but as Stuart Sierra has pointed out in a comment,
;; a Clojure built-in is available to accomplish the same
;; thing
([sym] (intern *ns* sym))
([sym val] (intern *ns* sym val)))
Note that if a Var turns out to have already been interned with the given name in the given namespace, then this changes nothing in the single argument case or just resets the Var to the given new value in the two argument case. With this, you can solve the original problem like so:
(dorun (map #(create-var (symbol %) 666) ["x" "y" "z"]))
Some additional examples:
user> (create-var 'bar (fn [_] :bar))
#'user/bar
user> (bar :foo)
:bar
user> (create-var 'baz)
#'user/baz
user> baz
; Evaluation aborted. ; java.lang.IllegalStateException:
; Var user/baz is unbound.
; It does exist, though!
;; if you really wanted to do things like this, you'd
;; actually use the clojure.contrib.with-ns/with-ns macro
user> (binding [*ns* (the-ns 'quux)]
(create-var 'foobar 5))
#'quux/foobar
user> quux/foobar
5
Evaluation rules for normal function calls are to evaluate all the items of the list, and call the first item in the list as a function with the rest of the items in the list as parameters.
But you can't make any assumptions about the evaluation rules for special forms or macros. A special form or the code produced by a macro call could evaluate all the arguments, or never evaluate them, or evaluate them multiple times, or evaluate some arguments and not others. def is a special form, and it doesn't evaluate its first argument. If it did, it couldn't work. Evaluating the foo in (def foo 123) would result in a "no such var 'foo'" error most of the time (if foo was already defined, you probably wouldn't be defining it yourself).
I'm not sure what you're using this for, but it doesn't seem very idiomatic. Using def anywhere but at the toplevel of your program usually means you're doing something wrong.
(Note: doall + for = doseq.)
I am learning the concept of sequence and nil in Clojure. This was the result of a small experimentation.
1:6 user=> (first '())
nil
1:7 user=> (rest '())
()
1:8 user=> (first (rest '()))
nil
Does this mean that '() is actually a sequence of nils?
If you want to test whether the "rest" of a collection is empty, use next.
user> (next '(foo bar))
(bar)
user> (next '())
nil
user> (doc next)
-------------------------
clojure.core/next
([coll])
Returns a seq of the items after the first. Calls seq on its
argument. If there are no more items, returns nil.
"nil-punning" (treating an empty collection/seq and nil as the same thing) was removed last year in favor of fully-lazy sequences. See here for a discussion leading up to this change.
first and rest are functions that apply to a logical structure (a seq) and not on the linked cons structure of a list (as in other lisps).
Clojure defines many algorithms in terms of sequences (seqs). A seq is a logical list, and unlike most Lisps where the list is represented by a concrete, 2-slot structure, Clojure uses the ISeq interface to allow many data structures to provide access to their elements as sequences.
http://clojure.org/sequences
The behavior is a result of the definition of the function and not determined by the primitive structure of the data.
No - an empty list is not the same as an infinite sequence of nils
This is relatively easy to show. Suppose we have:
(def infinite-nils (repeat nil)) ; an infinite lazy sequence of nils
(def empty-list '()) ; an empty list
They have different numbers of elements:
(count infinite-nils) => doesn't terminate
(count empty-list) => 0
Taking from them:
(take 10 infinite-nils) => (nil nil nil nil nil nil nil nil nil nil)
(take 10 empty-list) => ()
If you call seq on them you get
(seq inifinite-nils) => sequence of infinite nils
(seq empty-list) => nil
The confusion in the original can largely be resolved by understanding the following facts:
'() is a collection (a persistent list), not a sequence. However it is sequential, so you can call seq on it to convert it into sequence.
nil is the empty sequence - so therefore (seq '()) returns nil, as does (seq (rest '()))
first returns nil on an empty sequence - hence why (first (rest '())) is nil.
Also learning Clojure.
For empty sequences, rest returns a sequence for which seq returns nil.
That's why you get that behavior.
I assume this is to simplify recursing on sequences until they are empty, and probably other smartypants reasons...
Technically yes though not in a useful way.
"Does the sequence that is created by calling (seq '()) have an infinite number of nulls?"
the answer is yes becase the (rest) of an empty sequence is sill an empty sequence which it's self can have a (rest)
This output is misleading by the way:
1:7 user=> (rest '())
()
the first '() in this is the empty list.
the secong () in this is the empty sequence.
sequences are printed the same as lists in the repl even though they are not the same.