concatenating function that takes arbitrary inputs - clojure

I want to write a function that concatenates vectors or matrices, which can take arbitrary inputs. To combine two vectors I've written the follow code. It also also matrices to be combined such that columns are lengthened.
(defn concats
([x y] (vec (concat x y))))
Where I am stuck is extending the input to n vectors or matrices, and combining matrices to make longer rows.
Ex) (somefunction [[:a :b] [:c :d]] [[1 2] [3 4]] 2]
[[:a :b 1 2] [:c :d 3 4]]
The 2 in the input designates level to concatenate.

If you're not interested in "how it works", here's the solution right up front (note that level is zero-indexed, so what you've called the 1st level I'm calling the 0th level):
(defn into* [to & froms]
(reduce into to froms))
(defn deep-into*
[level & matrices]
(-> (partial partial mapv)
(iterate into*)
(nth level)
(apply matrices)))
The short answer for how it works is this: it iteratively builds up a function that will nest the call to into* at the correct level, and then applies it to the supplied matrices.
Regular old into, given a vector first argument, will concatenate the elements of the second argument onto the end of the vector. The into* function here is just the way I'm doing vector concatting on a variable number of vectors. It uses reduce to iteratively call into on some accumulated vector (which starts as to) and the successive vectors in the list froms. For example:
user> (into* [1 2] [3 4] [5 6])
> [1 2 3 4 5 6]
Now for deep-into*, I had to recognize a pattern. I started by hand-writing different expressions that would satisfy different "levels" of concatenation. For level 0, it's easy (I've extrapolated your example somewhat so that I can make it to level 2):
user> (into* [[[:a :b] [:c :d]]] [[[1 2] [3 4]]])
> [[[:a :b] [:c :d]] [[1 2] [3 4]]]
As for level 1, it's still pretty straightforward. I use mapv, which works just like map except that it returns a vector instead of a lazy sequence:
user> (mapv into* [[[:a :b] [:c :d]]] [[[1 2] [3 4]]])
> [[[:a :b] [:c :d] [1 2] [3 4]]]
Level 2 is a little more involved. This is where I start using partial. The partial function takes a function and a variable number of argument arguments (not a typo), and returns a new function that "assumes" the given arguments. If it helps, (partial f x) is the same as (fn [& args] (apply f x args)). It should be clearer from this example:
user> ((partial + 2) 5)
> 7
user> (map (partial + 2) [5 6 7]) ;why was six afraid of seven?
> (7 8 9)
So knowing that, and also knowing that I'll want to go one level deeper, it makes some sense that level 2 looks like this:
user> (mapv (partial mapv into*) [[[:a :b][:c :d]]] [[[1 2][3 4]]])
> [[[:a :b 1 2] [:c :d 3 4]]]
Here, it's mapping a function that's mapping into* down some collection. Which is kind of like saying: map the level 1 idea of (mapv into* ...) down the matrices. In order to generalize this to a function, you'd have to recognize the pattern here. I'm going to put them all next to each other:
(into* ...) ;level 0
(mapv into* ...) ;level 1
(mapv (partial mapv into*) ...) ;level 2
From here, I remembered that (partial f) is the same as f (think about it: you have a function and you're giving it no additional "assumed" arguments). And by extending that a little, (map f ...) is the same as ((partial map f) ...) So I'll re-write the above, slightly:
(into* ...) ;level 0
((partial mapv into*) ...) ;level 1
((partial mapv (partial mapv into*)) ...) ;level 2
Now an iterative pattern is becoming clearer. We're calling some function on ... (which is just our given matrices), and that function is an iterative build-up of calling (partial mapv ...) on into*, iterating for the number of levels. The (partial mapv ...) part can be functionalized as (partial partial mapv). This is a partial function that returns a partial function of mapving some supplied arguments. This outer partial isn't quite necessary because we know that the ... here will always be one thing. So we could just as easily write it as #(partial mapv %), but I so rarely get a chance to use (partial partial ...) and I think it looks pretty. As for the iteration, I use the pattern (nth (iterate f initial) n). Perhaps another example would make this pattern clear:
user> (nth (iterate inc 6) 5)
> 11
Without the (nth ...) part, it would loop forever, creating an infinite list of incrementing integers greater than or equal to 5. So now, the whole thing abstracted and calculated for level 2:
user> ((nth (iterate (partial partial mapv) into*) 2)
[[[:a :b][:c :d]]] [[[1 2][3 4]]])
> [[[:a :b 1 2] [:c :d 3 4]]]
Then, using the -> macro I can factor out some of these nested parantheses. This macro takes a list of expressions and recursively nests each into the second position of the successive one. It doesn't add any functionality, but can certainly make things more readable:
user> ((-> (partial partial mapv)
(iterate into*)
(nth 2))
[[[:a :b][:c :d]]] [[[1 2][3 4]]])
> [[[:a :b 1 2] [:c :d 3 4]]]
From here, generalizing to a function is pretty trivial--replace the 2 and the matrices with arguments. But because this takes a variable number of matrices, we will have to apply the iteratively-built function. The apply macro takes a function or macro, a variable number of arguments, and finally a collection. Essentially, it prepends the function or macro and the supplied arguments onto the final list, then evaluates the whole thing. For example:
user> (apply + [1 5 10]) ;same as (+ 1 5 10)
> 16
Happily, we can stick the needed apply at the end of the (-> ...). Here's my solution again, for the sake of symmetry:
(defn deep-into*
[level & matrices]
(-> (partial partial mapv)
(iterate into*)
(nth level)
(apply matrices)))

Using the concats function you listed in the question:
user=> (map concats [[:a :b] [:c :d]] [[1 2] [3 4]])
([:a :b 1 2] [:c :d 3 4])
this doesn't take into account the level as you listed, but it handles the input given
Taking arbitrary number of arguments needs a replacement concats function
(defn conc [a b & args]
(if (nil? (first args))
(concat a b)
(recur (concat a b) (first args) (rest args))))
Here are two examples
user=> (map conc [[:a :b] [:c :d]] [[1 2] [3 4]] [["w" "x"] ["y" "z"]])
((:a :b 1 2 "w" "x") (:c :d 3 4 "y" "z"))
user=> (map conc [[:a :b] [:c :d] [:e :f]] [[1 2] [3 4] [5 6]] [["u" "v"] ["w" "x"] ["y" "z"]])
((:a :b 1 2 "u" "v") (:c :d 3 4 "w" "x") (:e :f 5 6 "y" "z"))

Here are two different solutions for a function which will return a vector that's the concatenation of an arbitrary number of input collections:
(defn concats [& colls]
(reduce (fn [result coll]
(into result coll))
[]
colls))
(defn concats [& colls]
(vec (apply concat colls)))
The [& arg-name] notation in the argument lists is how you specify that the function is "variadic" - meaning it can accept a variable number of arguments. The result is that colls (or whatever name you pick) will be a sequence of all the arguments in excess of the positional arguments.
Functions can have multiple arities in Clojure, so you can also do things like this:
(defn concats
([x]
(vec x))
([x y]
(vec (concat x y)))
([x y & colls]
(vec (apply concat (list* x y colls)))))
However, only one of the overloads can be variadic, and its variadic part must come last (i.e. you can't do [& more n], only [n & more].
The Clojure.org page on special forms has more useful information on argument lists in Clojure (in the section on fn).
The function below correctly handles the example input/output you provided. Unfortunately I don't think I understand how you want the levels (and associated numeric input) to work well enough to generalize it as far as you're looking for.
(defn concats [x y]
;; only works with two inputs
(vec (map-indexed (fn [i v] (into v (nth y i)))
x)))
(concats [[:a :b] [:c :d]] [[1 2] [3 4]]) ;=> [[:a :b 1 2] [:c :d 3 4]]
But maybe it will give you some ideas anyway, or if you can add more information (especially examples of how different levels should work) I'll see if I can be more help.

Related

Using a mult-argument Predicate with Filter in Clojure

Is it possible to use filter with a predicate with multiple arguments? If so, how would I do it under the context of this code:
;predicate
(defn classInstructor [instructor class]
(str/includes? class instructor))
(defn instructorClasses [instructor classList]
(filter classInstructor classList))
The map function can take a function that applies to several arguments. For example,
=> (map + [1 2 3] [4 5 6])
(5 7 9)
The + gets two arguments, one from each sequence. There is no corresponding version of filter. You could extend the standard filter as follows:
(defn filter
([f coll]
(clojure.core/filter f coll))
([f coll & colls]
(filter #(apply f %) (apply map vector (cons coll colls)))))
For example,
=> (filter (comp odd? +) [1 2 3] [4 6 8])
([1 4] [3 8])
As you can see, we have to present the surviving sequences somehow. I don't find it persuasive or natural to do so. Not worth doing, I think.
I would do it like so, using an anonymous function:
(defn classInstructor [instructor class]
(str/includes? class instructor))
(defn instructorClasses [instructor classList]
(filter #(classInstructor instructor %) classList))
This way, when one calls instructorClasses, the value of instructor is passed through to classInstructor.

Return a sequence with the elements not in common to two original sequences by using clojure

I have two sequences, which can be vector or list. Now I want to return a sequence whose elements are not in common to the two sequences.
Here is an example:
(removedupl [1 2 3 4] [2 4 5 6]) = [1 3 5 6]
(removeddpl [] [1 2 3 4]) = [1 2 3 4]
I am pretty puzzled now. This is my code:
(defn remove-dupl [seq1 seq2]
(loop [a seq1 b seq2]
(if (not= (first a) (first b))
(recur a (rest b)))))
But I don't know what to do next.
I encourage you to think about this problem in terms of set operations
(defn extrasection [& ss]
(clojure.set/difference
(apply clojure.set/union ss)
(apply clojure.set/intersection ss)))
Such a formulation assumes that the inputs are sets.
(extrasection #{1 2 3 4} #{2 4 5 6})
=> #{1 6 3 5}
Which is easily achieved by calling the (set ...) function on lists, sequences, or vectors.
Even if you prefer to stick with a sequence oriented solution, keep in mind that searching both sequences is an O(n*n) task if you scan both sequences [unless they are sorted]. Sets can be constructed in one pass, and lookup is very fast. Checking for duplicates is an O(nlogn) task using a set.
I'm still new to Clojure but I think the functional mindset is more into composing functions than actually doing it "by hand", so I propose the following solution:
(defn remove-dupl [seq1 seq2]
(concat
(remove #(some #{%} seq1) seq2)
(remove #(some #{%} seq2) seq1)))
EDIT: I think it is better if we define that remove part as a local function and reuse it:
(defn remove-dupl [seq1 seq2]
(let [removing (fn [x y] (remove #(some #{%} x) y))]
(concat (removing seq1 seq2) (removing seq2 seq1))))
EDIT2: As commented by TimothyPratley
(defn remove-dupl [seq1 seq2]
(let [removing (fn [x y] (remove (set x) y))]
(concat (removing seq1 seq2) (removing seq2 seq1))))
There are several problems with your code.
It doesn't test for the end of either sequence argument.
It steps through b but not a.
It implicitly returns nil when any two sequences have the same
first element.
You want to remove the common elements from the concatenated sequences. You have to work out the common elements first, otherwise you don't know what to remove. So ...
We use
clojure.set/intersection to find the common elements,
concat to stitch the collections together.
remove to remove (1) from (2).
vec to convert to a vector.
Thus
(defn removedupl [coll1 coll2]
(let [common (clojure.set/intersection (set coll1) (set coll2))]
(vec (remove common (concat coll1 coll2)))))
... which gives
(removedupl [1 2 3 4] [2 4 5 6]) ; [1 3 5 6]
(removedupl [] [1 2 3 4]) ; [1 2 3 4]
... as required.

In Clojure, second argument in map-indexed

SPOILER ALERT: This is about answers to 4Clojure question 157, indexing sequences.
The fast version of this question: in (map-indexed #(vector %2 %1) [:a :b :c]), what is %2?
Indexing Sequences #157
Transform a sequence into a sequence of pairs containing the original elements along with their index.
(= (__ [:a :b :c]) [[:a 0] [:b 1] [:c 2]])
(= (__ [0 1 3]) '((0 0) (1 1) (3 2)))
(= (__ [[:foo] {:bar :baz}]) [[[:foo] 0] [{:bar :baz} 1]])
I pretty quickly managed an answer: #(map reverse (map-indexed vector %)), but saw seemingly better answers such as:
map-indexed #(vector %2 %1)
by user tomdmitriev.
The question: where does the second argument come from?
So, for (map-indexed #(vector %2 %1) [:a :b :c]), what is %2?
The docs for map-indexed state:
Returns a lazy sequence consisting of the result of applying f to 0
and the first item of coll, followed by applying f to 1 and the second
item in coll, etc, until coll is exhausted. Thus function f should
accept 2 arguments, index and item. Returns a stateful transducer when
no collection is provided. -- my emphasis
Well, I also only provided one argument, the collection from the 4Clojure question. I'm not sure how this is working... is there some kind of an implied or implicit argument?
Thanks for any help clearing this up!
The function passed to map-indexed is a function of [index item]. Easy to understand with:
(map-indexed (fn [idx itm] [idx itm]) "item")
; ([0 "item"])
It is actually a apply_map_with_index
So back to your example, with:
(map-indexed #(vector %2 %1) [:a :b :c])
; ([:a 0] [:b 1] [:c 2])
Will create a small sequence of vector, made from %2 the item, %1 the index.
You can also compare the above with the easy to understand:
(map-indexed #(vector %1 %2) [:a :b :c])
; ([0 :a] [1 :b] [2 :c])
which creates a sequence of small vector of [index item].
EDIT:
If we decompose this in two steps, it gives:
; we need to define a function
; with two parameters
(defn my-function [index item]
(vector item index))
; map-indexed uses a function with
; two parameters
(map-indexed
my-function
[:a :b :c])

How to transpose a nested vector in clojure

I have the following variable
(def a [[1 2] [3 4] [5 6]])
and want to return
[[1 3 5][2 4 6]]
and if input is
[[1 2] [3 4] [5 6] [7 8 9]] then the required result is
[[1 3 5 7] [2 4 6 8] [9]]
How to do it in clojure?
(persistent!
(reduce
(fn [acc e]
(reduce-kv
(fn [acc2 i2 e2]
(assoc! acc2 i2 ((fnil conj []) (get acc2 i2) e2)))
acc
e))
(transient [])
[[1 2 3] [:a :b] [\a] [111] [200 300 400 500]]))
;;=> [[1 :a \a 111 200] [2 :b 300] [3 400] [500]]
An empty vector can be updated via the update-in fn at the 0th index, a non-empty vector can be, additionally, updated at the index immediately following the last value.
The reduction here is about passing the outer accumulator to the inner reducing function, updating it accordingly, and then returning it back to the outer reducing function, which in turn will pass again to the inner rf for processing the next element.
EDIT: Updated to fastest version.
I like ifett's implementation, though it seems weird to use reduce-kv to build a vector that could be easily build with map/mapv.
So, here is how I would've done it:
(defn transpose [v]
(mapv (fn [ind]
(mapv #(get % ind)
(filter #(contains? % ind) v)))
(->> (map count v)
(apply max)
range)))
(->> (range)
(map (fn [i]
(->> a
(filter #(contains? % i))
(map #(nth % i)))))
(take-while seq))
Notice that this algorithm creates a lazy seq of lazy seqs so you that you will only pay for the transformations you really consume. If you insist on creating vectors instead, wrap the forms in vec at the necessary places - or if you are using Clojurescript or don't mind a Clojure 1.7 alpha use transducers to create vectors eagerly without paying for laziness or immutability:
(into []
(comp
(map (fn [i]
(into [] (comp (filter #(contains? % i))
(map #(nth % i)))
a)))
(take-while seq))
(range))
I find this easy to understand:
(defn nth-column [matrix n]
(for [row matrix] (nth row n)))
(defn transpose [matrix]
(for [column (range (count (first matrix)))]
(nth-column matrix column)))
(transpose a)
=> ((1 3 5) (2 4 6))
nth-column is a list comprehension generating a sequence from the nth element of each sequence (of rows).
Then transpose-matrix is simply iterating over the columns creating a sequence element for each, consisting of (nth-column matrix column) i.e. the sequence of elements for that column.
(map
(partial filter identity) ;;remove nil in each sub-list
(take-while
#(some identity %) ;;stop on all nil sub-list
(for [i (range)]
(map #(get % i) a)))) ;; get returns nil on missing values
Use get to have nil on missing values, iterate (for) on an infinite range, stop on all nil sub-list, remove nil from sub-lists. Add vector constructor before first map and in it's function (first argument) if you really need vectors.
EDIT: please leave a comment if you think this is not useful. We can all learn from mistakes.

Clojure - map-indexed is it possible to start with an index other than 0?

Usually map-indexed function maps each list item to a respective index where the first index is 0, the second is 1 etc.
Is it possible to have the index start at another number and proceed from there?
Easiest way is to just remember that you can pass multiple sequences to map.
(map vector [:a :b :c] (iterate inc 100))
=> ([:a 100] [:b 101] [:c 102])
You simply wrap the index with another function in the receiving function
For example if we wanted to start at 1 instead of zero we would simply use inc
(map-indexed (fn [i v] (vector (inc i) v)) ["one" "two" "three"])
Will return
([1 "one"] [2 "two"] [3 "three"])
map-indexed does not allow this. However, it's easy to write your own version that lets you do it.
(defn map-indexed-from [n f coll]
(map f (range n Double/POSITIVE_INFINITY) coll))
Example usage:
user> (map-indexed-from 5 vector [:a :b :c])
([5 :a] [6 :b] [7 :c])