I have a homework problem that requires me to print (in a vector) a specified nth index from a vector of vectors. For examples, if I enter [1 2 3 4] [5 6 7 8] [9 10 11 12] and enter my function specifying the nth index 1, my result has to be [2 6 10].
Very confused, not good at Clojure, just a Java/Python person.
I've already tried using a function that accepts vector and a variable to serve as the nth. But it returns the whole vectors AND the value entered for x.
(defn column [vector x]
(cond
(empty? vector)
nil
:else
(column (nth vector x))))
If I enter:
user ==> column vector 0
Result is this:
[1 2 3 4] [5 6 7 8] [9 10 11 12]
0
Instead of:
[1 5 9]
An idiomatic clojure way of solving this would be with the use of map
(def v [[1 2 3 4] [5 6 7 8] [9 10 11 12]])
(defn column [coll pos]
(map #(nth % pos) coll))
the nth function gives the nth element in the vector. The map function will iterate over each of the inner vectors and call nth on it with the given column value.
The result will be a sequence of value from the required column.
Related
I'm trying to solve the square sum problem, more specifically creating a function that can help with the relations.
"the function should, given a set A of integers, produce a relation that includes tuple [a b],
iff a and b are in A and their sum is a square number"
To my aid, I got a help function square?, that tests whether a passed integer is a squared number.
(defn square?
[n]
(= n (sqr (isqrt n)))
)
I took a shot in dark with this, but honestly I'm lost.
(defn sqr-sum-rel
[A]
(reduce (fn [a b] (
if (square? (a + b))
[a b]
)) A )
)
Testing the function should return something like this:
(test? "test" (sqr-sum-rel (set (range 1 11))) #{[5 4] [2 2] [8 8] [4 5] [7 9] [1 3] [3 6] [6 10] [2 7] [1 8] [8 1] [7 2] [10 6] [6 3] [3 1] [9 7]})
I'm really new to Clojure and even functional programming in general, so any pointers in the right direction are appreciated.
To solve this problem, you can first generate all possible pairs of numbers from the set using for and then filter those pair. Assuming square? is properly implemented, we write a helper function that will be the first argument that we pass to filter:
(defn sum-is-square? [coll]
(square? (apply + coll)))
It takes a collection of numbers as argument and test if their sum is square?. Then we can write the complete function like
(defn sqr-sum-rel [A]
(set (filter sum-is-square? (for [a A
b A]
[a b]))))
that takes as argument a set A and first produces all pairs that can be formed by elements from this set, and then only keep those pairs for which sum-is-square? evaluates to true.
We can test it by passing in a set of numbers:
(sqr-sum-rel (set (range 1 11)))
;; => #{[8 8] [2 2] [7 2] [5 4] [6 3] [1 3] [1 8] [8 1] [7 9] [2 7] [3 6] [10 6] [4 5] [9 7] [3 1] [6 10]}
Added: A briefer implementation as suggested by the original poster uses the :when option of for:
(defn sqr-sum-rel [A]
(set (for [a A
b A :when (square? (+ a b))]
[a b]))))
i would also guess that the the number in set can't form the pair with itself, and also there is no need to compare pair members in reverse order, since we already know they form the relation needed. I would update it like this:
(defn sq-rel [a-set]
(seq (for [[x & t] (take-while seq (iterate rest a-set))
y t
:when (square? (+ x y))]
[x y])))
this one is more or less like an imperative
for (i = 0; i < len; i++) {
for (j = i + 1; j < len; j++)
if (isSquare(a[i] + a[j])) {
res.push([a[i], a[j]])
}
}
}
in repl:
user> (sq-rel #{1 2 3 4 5 6})
;;=> ([1 3] [4 5] [6 3])
How can I make in Clojure functions vector-fold and vector-map from scheme?
To map over a vector and get a vector back you can use mapv.
To fold over a vector you can use regular reduce since vectors are seqable.
To get an index in the function you're iterating with, there's map-indexed or you can use (range):
(mapv (fn [i e] [i e]) [1 2 3] (range))
=> [[1 0] [2 1] [3 2]]
I was surprised to discover that clojure vectors implement the Associative interface.
(associative? [1 2 3]) ; => true
I assume this interface provides optimized indexing by keys. Following this assumption, the interface seems appropriate for map data structures, but odd for vectors, which don't follow a key-value heuristic in my mind.
Is my mental model for Associative or vector's implementation incorrect? What purpose does this design choice serve?
It may not seem intuitive initially, but vectors are keyed by their indices, which allow them to make use of all the standard associative functions. This makes it very easy to do simple operations on them:
(def v [1 2 3])
(assoc v 1 4)
[1 4 3]
(update v 1 inc)
[1 3 3]
(get v 1) ; The same as (v 1)
2
Or, if you have a 2D vector:
(def v [[1 2 3]
[4 5 6]
[7 8 9]])
(assoc-in v [2 1] 0)
[[1 2 3]
[4 5 6]
[7 0 9]]
Without this design choice, an entire separate set of functions would need to be created and used specifically for vectors. Having a standardized interface allows you to write functions that don't care about specifically what structure they're working on.
Think about it this way: Say you wanted to write a function that "replaces" an element of a vector. Would its signature be any different from the existing assoc function; besides specifically expecting a vector?
Clojure vectors associate an index with a value. This means you can do things like this:
(assoc [0 1] 0 2)
(reduce-kv (fn [m idx v]
(assoc m idx v)) {} [0 1 2])
And both are efficient.
I am trying to write a function in clojure returns cartesian product
(my-compute-fn [1 2 3] [4 5 6])
will return
[[1 4] [1 5] [1 6] [2 4] [2 5] ....]
My attempt resulted in this
(defn compute [col1 col2]
(let [totcol2 (count col2)
totcol1 (count col2)]
(map #(vector %1 %2)
(mapcat #(repeat totcol1 %1) col1)
(take (* totcol1 totcol2) (cycle col2)))))
Which does the job, but looks a bit clunky.
What would be a better and more concise implementation, involving more readily available functions from clojure.core?
Thanks!
edit:
Found clojure combinatorics, and it doesn't seem there's a magic functional way of doing this.
for is the prime candidate for this task:
(for [a [1 2 3]
b [4 5 6]]
[a b])
;; => ([1 4] [1 5] [1 6] [2 4] [2 5] [2 6] [3 4] [3 5] [3 6])
You can supply for with any number of seqs and it will bind the given symbols to each element of the seq associated with them. There is even cooler stuff like :when that lets you e.g. find all those products whose sum is 7:
(for [a [1 2 3]
b [4 5 6]
:when (= (+ a b) 7)]
[a b])
;; => ([1 6] [2 5] [3 4])
Let's say i have the following vector
(def x [[1 2 3] [4 5 6] [7 8]])
and I want to append the number 9 to the last vector (I don't know the index of the vector)
(conj (vec (butlast x)) (conj (last x) 9))
#=> [[1 2 3] [4 5 6] [7 8 9]]
Is there a better/clearer way to do this?
Use the efficient tail access functions
(conj (pop x) (conj (peek x) 9))
But you could also
(update-in x [(dec (count x))] conj 9)