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.
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])
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.
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]]
Hi all I am new at learning Scheme and often have issues with making parallels between an imperative language and a functional language.
For example if I had had two arrays.
A = [1 2 3]
B = [4 5 6]
If I wanted to create a new array with the elements of A multiplied by each element in B I could simply do something like (pseudo-code):
for(int i = 0; i < A.length; i++)
for(int j = 0; j < B.length, j++)
arr.push(A[i]*B[j])
Which would give back:
arr = [4 5 6 8 10 12 12 15 18]
What would be some ways to approach this problem in a functional language?
In Scheme, the most common data structure is the linked list. Unless you have to access elements by index, it's always preferred to use lists, as there are countless built-in procedures for handling lists, that make easy to implement most algorithms without ever using an index. Just remember that for efficient access by index, using a vector would be a better idea.
Having said that, and depending on the Scheme dialect that you're using, the solution can be as simple as this (in Racket, see the documentation):
(define a '(1 2 3))
(define b '(4 5 6))
(for*/list ([x a] [y b])
(* x y))
=> '(4 5 6 8 10 12 12 15 18)
Alternatively, using only standard Scheme:
(apply append
(map (lambda (x)
(map (lambda (y) (* x y))
b))
a))
In Scheme and Racket arrays (array: a data structure indexed by a natural number) is represented using vectors.
(define as (vector 1 2 3))
(define bs (vector 4 5 6))
To make a loop-inside-a-loop we will use a variant of for*.
Plain for* works like this:
(for* ([a as] [b bs])
(displayln (* a b))))
Here a runs through the elements of the vector as and b runs through the elements in bs. Since for* is used, the b-loop runs inside the a-loop.
If for is used instead the loops run in parallel (try it).
Now since we want to collect the element, we can use for*/vector which stores the generated elements in a vector:
(for*/vector ([a as] [b bs])
(* a b)))
For efficiency reason, one can write:
(for*/vector ([a (in-vector as)] [b (in-vector bs)])
(* a b)))
This will generate sligthly more efficient code.
However
(for*/vector ([a as] [b bs])
(* a b)))
will also work if as and bs are lists.
Problem: I've got a collection of vectors or lists which I would like to find an idiomatic way to sum onto an existing vector possibly with uneven sized vectors.
Contrived example showing the setup:
=>(def collated-list [2 3 4 5 6 7 8])
=>(def lists-to-add (partition-all 3 collatedlist))
=>(def base-list [1 1 1])
I'd like the result to sum the broken down collated lists onto the base-list, for example, the first item would be 1 + 2 + 5 + 8 and so on.
What I've tried: I've tried a map and a for loop in couple of different ways but I seem to encounter either problems with Lazy Sequencing or problems of trying to add an Integer to a Vector.
These are my first experiments with Clojure so it's almost certainly me mis-understanding functional iteration here.
Thanks
First of all, it'll be much easier if lists-to-add contains lists of even length, so use partition instead of partition-all:
(def lists-to-add (partition 3 3 '(0 0) collated-list))
And then you can do the summing with map and recursion:
(defn sum-lists [base-lists lists-to-add]
(reduce #(map + %1 %2) base-list lists-to-add))
; List of list
(def lst (partition 5 (range 200)))
; Base list
(def base [1 1 1 1 1])
; Sum operation
(apply map (fn [& args] (apply + args) ) base lst)