How can i loop through a Collection in Clojure? - clojure

I have a Matrix and i want to print the rows of it.
I tried to implement it like this but i dont know how to loop and get the other elements!
(defn p! [args]
(println (first args))
(drop args))
(p! [[1 2] [3 4]]) --> [1 2]
the output should look like this
;; 12
;; 34

I would suggest using the core.matrix facilities for this task. It has a mature and time-tested API. Among other things, it provides you with a pm function that pretty-prints a matrix and accepts a custom element formatter as a parameter.
You might find its implementation interesting, since it can give you an idea of printing array-like structures. (TL;DR: It approaches it with a recursive algorithm that employs a dotimes fn quite heavily.)
With this library you might end up implementing your p! fn like this:
(require '[clojure.core.matrix :as mx])
(defn p! [args]
(mx/pm (mx/matrix args)))
(p! [[1 2] [3 4]])
[[1 2]
[3 4]]
=> nil
If you would like to keep things simple and/or omit the brackets, then the easiest implementation would be along these lines:
(defn p! [args]
(doseq [row args]
(println (clojure.string/join " " row))))
(p! [[1 2] [3 4]])
1 2
3 4
=> nil
Cheers!

Related

Can avoiding nil conjoins be done better?

I have a token scanner that simply returns nil for characters I'm not interested in. Rather than conj the nils to my token vector and then later stripping them all out, I want to simply not add them.
I'm using
;; dont conjoin if value false
(defn condj [v val]
(cond-> v, val (conj val)))
to do this. Is there a specific operator or a more concise implementation?
I believe you can use transducers for this. They are explained here. Our reducing function is conj and we construct a transducer (remove nil?) that turns this function into one that will ignore nil:
(def condj ((remove nil?) conj))
Note that remove is the opposite of filter. We can also implement condj using (filter some?), some? being a function that is true for any value except nil:
(def condj ((filter some?) conj))
It seems to work:
user=> (condj [3 4 5] 9)
[3 4 5 9]
user=> (condj [3 4 5] nil)
[3 4 5]
user=> (condj [3 4 5] false)
[3 4 5 false]
I like the cond-> version and often use that to avoid repetition in the if version. Don't forget to be explicit about false values, though. I also like to use Plumatic Schema to be explicit about the data shape entering and leaving the function:
(ns tst.demo.core
(:use tupelo.core tupelo.test)
(:require
[schema.core :as s]))
(s/defn condj :- [s/Any]
"Conjoin an item onto a vector of results if the item is not nil."
[accum :- [s/Any]
item :- s/Any]
(cond-> accum
(not (nil? item)) (conj item)))
(dotest
(let [result (-> []
(condj :a)
(condj :2)
(condj false)
(condj "four")
(condj nil)
(condj "last"))]
; nil is filtered but false is retained
(is= result [:a :2 false "four" "last"])))
You may also be interested in another version using my favorite library:
(s/defn condj :- [s/Any]
"Conjoin an item onto a vector of results if the item is not nil."
[accum :- [s/Any]
item :- s/Any]
(cond-it-> accum
(not-nil? item) (append it item)))
For more complicated forms, using the placeholder symbol it makes it explicit where the value is being threaded. I also like the convenience functions not-nil? and append since they also make the intent of the code plainer.
I think the overly simplified approach is the cleanest here (it's also slightly more concise):
(defn condj [v val]
(if val (conj v val) v))
I find that this is much easier to understand quickly. The only downside is v is duplicated since it isn't being threaded, but that's not a big loss in such a simple function.
Consider using into instead of conj:
(into [1 2 3] nil) ;=> [1 2 3]
(into [1 2 3] [4]) ;=> [1 2 3 4]
Note: the downside is you must return results in a sequence which adds a bit of overhead. However, if you forget to do this you get an error, it makes it easy to extend the logic when you want to append more than one item, the code is easily understandable and doesn't require any custom functions to be created.

Good way in clojure to map function on multiple items of coll or seqence

I'm currently learning Clojure, and I'm trying to learn how to do things the best way. Today I'm looking at the basic concept of doing things on a sequence, I know the basics of map, filter and reduce. Now I want to try to do a thing to pairs of elements in a sequence, and I found two ways of doing it. The function I apply is println. The output is simply 12 34 56 7
(def xs [1 2 3 4 5 6 7])
(defn work_on_pairs [xs]
(loop [data xs]
(if (empty? data)
data
(do
(println (str (first data) (second data)))
(recur (drop 2 data))))))
(work_on_pairs xs)
I mean, I could do like this
(map println (zipmap (take-nth 2 xs) (take-nth 2 (drop 1 xs))))
;; prints [1 2] [3 4] [5 6], and we loose the last element because zip.
But it is not really nice.. My background is in Python, where I could just say zip(xs[::2], xs[1::2]) But I guess this is not the Clojure way to do it.
So I'm looking for suggestions on how to do this same thing, in the best Clojure way.
I realize I'm so new to Clojure I don't even know what this kind of operation is called.
Thanks for any input
This can be done with partition-all:
(def xs [1 2 3 4 5 6 7])
(->> xs
(partition-all 2) ; Gives ((1 2) (3 4) (5 6) (7))
(map (partial apply str)) ; or use (map #(apply str %))
(apply println))
12 34 56 7
The map line is just to join the pairs so the "()" don't end up in the output.
If you want each pair printed on its own line, change (apply println) to (run! println). Your expected output seems to disagree with your code, so that's unclear.
If you want to dip into transducers, you can do something similar to the threading (->>) form of the accepted answer, but in a single pass over the data.
Assuming
(def xs [1 2 3 4 5 6 7])
has been evaluated already,
(transduce
(comp
(partition-all 2)
(map #(apply str %)))
conj
[]
xs)
should give you the same output if you wrap it in
(apply println ...)
We supply conj (reducing fn) and [] (initial data structure) to specify how the reduce process inside transduce should build up the result.
I wouldn't use a transducer for a list that small, or a process that simple, but it's good to know what's possible!

Can I transduce / educe over multiple collections without concatting them

Below is a bare-bones version of what I'm doing:
(eduction (map inc) (concat [1 2] [3 4]))
; -> (2 3 4 5)
Is there a way to get the same eduction, without having to pay the cost of concat, which creates an intermediate lazy seq?
The following would perhaps already be a bit less wasty, as instead of the lazy seq, we just have a vector, but I wonder if even that can be avoided.
(eduction (comp cat (map inc)) [[1 2] [3 4]])
It may be simplest to process your collections separately and combine the results. There is, in fact, an easy reducers-based solution that does exactly that under the covers.
The clojure.core.reducers namespace has cat, a combining function for fold, that you can repurpose to construct a reducible concatenation of your vectors.
(require '[clojure.core.reducers :as r])
(eduction (map inc) (r/cat [1 2] [3 4]))
;; => (2 3 4 5)
This avoids the lazy sequence used in concat. If you have more than two vectors, you can concatenate them all with (reduce r/cat [] colls) or similar.
This approach did speed up some of the experiments I did, though not your particular example.
You can also do this without the reducer just using the built in cat transducer
(eduction (comp cat (map inc)) [[1 2] [3 4]])
;; => (2 3 4 5)

Clojure Print the contents of a vector

In Clojure, how do you print the contents of a vector? (I imagine to the console, and usually for debugging purposes). If the answer can be generalized to any Seq that would be good.
Edit:
I should add that it should be a simple function that gives output that looks reasonable, so prints an item per line - so can be easily used for debugging purposes. I'm sure there are libraries that can do it, but using a library really does seem like overkill.
I usually use println. There are several other printing functions that you might want to try. See the "IO" section of the Clojure cheatsheet.
This isn't Java. Just print it, and it will look OK.
You can also use clojure.pprint/pprint to pretty-print it. This can be helpful with large, complex data structures.
These methods work for all of the basic Clojure data structures.
Exception: Don't print infinitely long lazy structures such as what (range) returns--for obvious reasons. For that you may need to code something special.
This works for me:
(defn pr-seq
([seq msg]
(letfn [(lineify-seq [items]
(apply str (interpose "\n" items)))]
(println (str "\n--------start--------\n"
msg "\nCOUNT: " (count seq) "\n"
(lineify-seq seq) "\n---------end---------"))))
([seq]
(pr-seq seq nil)))
Example usages:
(pr-seq [1 2 3])
(pr-seq (take 20 blobs) (str "First 20 of " (count blobs) " Blobs")))
If you want to just print out the elements of the sequence/vector you could just map println to your sequence/vector, but make sure you force map to evaluate using dorun:
(dorun (map println [1 2 3 4]))
This can be applied to sequences too:
(dorun (map println '(1 2 3 4)))
Another way you can do this with apply is to curry map with println and apply it to the sequence/vector:
(apply (partial map println) [[1 2 3 4]])
(apply (partial map println) ['(1 2 3 4)])
Another way you can do this is with doseq:
(doseq [e [1 2 3 4]]
(println e))
(doseq [e '(1 2 3 4)]
(println e))
This one at least stops the text going out too far to the right:
(defn pp
([n x]
(binding [pp/*print-right-margin* n]
(-> x clojure.pprint/pprint)))
([x]
(pp 100 x)))
It is possible to do partials of this function to alter the width.

How to iterate over ArrayMap in clojure?

I am totally new to clojure (started learning yesterday) and functional programming so please excuse my ignorance. I've been trying to read a lot of the clojure documentation, but much of it is totally over my head.
I'm trying to iterate over an ArrayMap of this set up:
{city1 ([[0 0] [0 1] [1 1] [1 0]]), city2 ([[3 3] [3 4] [4 4] [4 3]]), city3 ([[10 10] [10 11] [11 11] [11 10]])}
(^hopefully that syntax is correct, that is what it looks like my terminal is printing)
where the city name is mapped to a vector of vectors that define the points that make up that city's borders. I need to compare all of these points with an outside point in order to determine if the outside point is in one of these cities and if so which city it is in.
I'm using the Ray Casting Algorithm detailed here to determine if an outside point is within a vector of vectors.
Maps actually implement the clojure.lang.ISeq interface which means that you can use all the higher-level sequence operations on them. The single elements are pairs of the form [key value], so, to find the first element that matches a predicate in-city? you could e.g. use some:
(some
(fn [[city-name city-points]] ;; the current entry of the map
(when (in-city? the-other-point city-points) ;; check the borders
city-name)) ;; return the name of a matching city
cities)
You might also use keep to find all elements that match the predicate but I guess there is no overlap between cities in your example.
Update: Let's back off a little bit, since working with sequences is fun. I'm not gonna dive into all the sequence types and just use vectors ([1 2 3 ...]) for examples.
Okay, for a start, let's access our vector:
(first [1 2 3]) ;; => 1
(rest [1 2 3]) ;; => [2 3]
(last [1 2 3]) ;; => 3
(nth [1 2 3] 1) ;; => 2
The great thing about functional programming is, that functions are just values which you can pass to other functions. For example, you might want to apply a function (let's say "add 2 to a number") to each element in a sequence. This can be done via map:
(map
(fn [x]
(+ x 2))
[1 2 3])
;; => [3 4 5]
If you haven't seen it yet, there is a shorthand for function values where % is the first parameter, %2 is the second, and so on:
(map #(+ % 2) [1 2 3]) ;; => [3 4 5]
This is concise and useful and you'll probably see it a lot in the wild. Of course, if your function has a name or is stored in a var (e.g. by using defn) you can use it directly:
(map pos? [-1 0 1]) ;; => [false false true]
Using the predicate like this does not make a lot of sense since you lose the actual values that produce the boolean result. How about the following?
(filter pos? [-1 0 1]) ;; => [1]
(remove pos? [-1 0 1]) ;; => [-1 0]
This selects or discards the values matching your predicate. Here, you should be able to see the connection to your city-border example: You want to find all the cities in a map that include a given point p. But maps are not sequences, are they? Indeed they are:
(seq {:a 0 :b 1}) ;; => [[:a 0] [:b 1]]
Oh my, the possibilities!
(map first {:a 0 :b 1}) ;; => [:a :b]
(filter #(pos? (second %)) {:a 0 :b 1}) ;; => [[:b 1]]
filter retrieves all the matching cities (and their coordinates) but since you are only interested in the names - which are stored as the first element of every pair - you have to extract it from every element, similarly to the following (simpler) example:
(map first (filter #(pos? (second %)) {:a 0 :b 1}))
:: => [:b]
There actually is a function that combines map and filter. It's called keep and return every non-nil value its predicate produces. You can thus check the first element of every pair and then return the second:
(keep
(fn [pair]
(when (pos? (second pair))
(first pair)))
{:a 0 b 1})
;; => [:b]
Everytime you see yourself using a lot of firsts and seconds, maybe a few rests inbetween, you should think of destructuring. It helps you access parts of values in an easy way and I'll not go into detail here but it can be used with sequences quite intuitively:
(keep
(fn [[a b]] ;; instead of the name 'pair' we give the value's shape!
(when (pos? b)
a))
{:a 0 :b 1})
;; => [:b]
If you're only interested in the first result you can, of course, directly access it and write something like (first (keep ...)). But, since this is a pretty common use case, you get some offered to you by Clojure. It's like keep but will not look beyond the first match. Let's dive into your city example whose solution should begin to make sense by now:
(some
(fn [[city-name city-points]]
(when (in-city? p city-points)
city-name))
all-cities)
So, I hope this can be useful to you.