How can I rewrite this Ruby code in Clojure?
seq = [1, 2, 3, 4, 5].each_cons(2)
#=> lazy Enumerable of pairs
seq.to_a
=> [[1, 2], [2, 3], [3, 4], [4, 5]]
Clojure:
(??? 2 [1 2 3 4 5])
;=> lazy seq of [1 2] [2 3] [3 4] [4 5]
What you are asking for is called sliding window over a lazy sequence.This way you can achieve that
user=> (partition 2 1 [1 2 3 4 5])
((1 2) (2 3) (3 4) (4 5))
Related
[6, 4, 3, 7, 2, 9, 1, 5]
[6, 4], [3, 7, 2], [9, 1, 5]
[6, 4], [3], [7], [2], [9], [1], [5]
swap
[6, 4], [3], [7], [2], [9], [1], [5]
[4, 6], [2, 3, 7], [1, 5, 9]
[2, 3, 4, 6, 7], [1, 5, 9]
[1, 2, 3, 4, 5, 6, 7, 9]
Is this correct? And why is this n log base 3 n?
The merge operations should be 3 way:
[6] [4] [3] [7] [2] [9] [1] [5]
[3 4 6] [2 7 9] [1 5]
[1 2 3 4 5 6 7 9]
|N|J|H|Q|6|L|K|5|P|E|3|A|G|8|D|4|O|I|B|0|9|M|F|2|1|C|7|
|H J N|6 L Q|5 K P|3 A E|8 D G|4 I O|0 9 B|2 F M|1 7 C|
|5 6 H J K L N P Q|3 4 8 A D E G I O|0 1 2 7 9 B C F M|
|0 1 2 3 4 5 6 7 8 9 A B C D E F G H I J K L M N O P Q|
I'm trying to build a pair generator. It takes a list of six names, and generates pairs for the week (5 days), with as few replications as possible.
The minimum I've gotten my replicated pairs down to is 2 (so I have found 5 days of pairs, i.e. 15 total pair combinations, with only 2 identical sets).
My method:
# Start with individuals in an array
[1, 2, 3, 4, 5, 6]
# Bisect the array
[1, 2, 3]
[4, 5, 6] => yields pair combinations [1, 4], [2, 5], [3, 6]
# Move the lower of the bisected arrays along
[1, 2, 3]
[6, 4, 5] => yields pair combinations [1, 6], [2, 4], [3, 5]
# Move along once more
[1, 2, 3]
[5, 6, 4] => yields pair combinations [1, 5], [2, 6], [3, 4]
# Since there are no more unique pair combinations, bisect each array again
(Array 1) [1, 2]
(Array 1) [3] => yields pair combination [1, 3] with 2 'spare'
(Array 2) [4, 5]
(Array 2) [6] => yields pair combination [4, 6] with 6 'spare'
=> 'spare' pair combination [2, 6] is a replication
# Move the lower of the bisected arrays along
(Array 1) [1, 2]
(Array 1) [3] => yields pair combination [2, 3] with 1 'spare'
(Array 2) [4, 5]
(Array 2) [6] => yields pair combination [5, 6] with 4 'spare'
=> 'spare' pair combination [1, 4] is a replication
This process above gives us 13 unique pairs, and then 2 that are non-unique. Every day of the week is covered, but we replicate.
Is there any way to do this more efficiently/to avoid the replication?
This is a round robin tournament where every player plays every other player. Line up the players like below to form the pairs 1 4, 2 5 and 3 6:
123
456
fix player 1, rotate the remaining players:
142
563
to produce pairs 1 5, 4 6 and 2 3. Keep rotating:
154
632
165
324
136
245
I think you're simply after the built-in combination method which returns an enumerator. You can use .to_a to turn it into an array of unique combinations.
[1, 2, 3, 4, 5, 6].combination(2).to_a
# => [[1, 2], [1, 3], [1, 4], [1, 5], [1, 6], [2, 3], [2, 4], [2, 5], [2, 6], [3, 4], [3, 5], [3, 6], [4, 5], [4, 6], [5, 6]]
This is called a 1-factorization. One 1-factorization of the complete graph on 6 vertices {0,1,2,3,4,oo} is to let the schedule on day i be {{oo,i},{i+1,i+4},{i+2,i+3}} where all of the numbers i+j are reduced mod 5.
Suppose I have a Clojure matrix A as such (formatted for clarity)
[[1 4 3]
[1 7 3]
[1 8 3]]
Now suppose I want to update the first column in place, by e.g. multiplying it by a factor of two, so that the new matrix becomes
[[2 4 3]
[2 2 3]
[2 8 3]]
How would one do this in clojure? I have tried things like assoc and stuff like
(join-along 1 (* (slice A 1 0) 2) (select A [0 1 2] [2 3]))
Naturally that did not work. It would be great if there was something like assoc for matrices e.g.
(massoc A [rows] [columns] replacement-vector)
or something simple like numpy in Python:
A[:,0]*2 = [[2 4 3]
[2 2 3]
[2 8 3]]
Thanks
You should look into clojure.core/matrix and see if it supports operations like this.
Here is something that may be what you're looking for. It should be trivial to change this to assoc a new value rather than updating after applying a function.
(defn mupdate-in
"Update all `coll' rows at `column' with `f'"
[coll column f & args]
(reduce #(apply update-in %1 [%2 column] f args)
coll
(range (count coll))))
An example:
(def m [[1 4 3]
[1 7 3]
[1 8 3]])
(mupdate-in m 0 * 2)
;; [[2 4 3]
;; [2 7 3]
;; [2 8 3]]
(mupdate-in m 2 + 10)
;; [[1 4 13]
;; [1 7 13]
;; [1 8 13]]
I asked a related question before:
Update matrix in-place in Clojure
And unfortunately, being new to Clojure, I am even more confused now.
Essentially what I would like to do, in Python syntax, is simply, with matrix A:
[[1 4 3]
[1 7 3]
[1 8 3]]
take the determinant of A, call it D, and then do
A[:,0] = A[:,0]*(D /abs(D))
upon which I would like to do
A = A*(D**(-1./A.shape[0]))
But even while perusing the functionality of core.matrix it is proving very difficult to figure out how something quite as simple is done in Clojure, even with the help of the previous question.
I have got this far [in clojure syntax]:
(join-along 1 (* (slice A 1 0) (/ (det A) (abs (det A)))) (select A [0 1 2] [1 2]))
but then then how to update in-place, without storing in variable? Currently getting error message:
Unidentified exception when trying to call procedure join-along with arguments (1 [1.0 4.0 7.0] #<NDWrapper [[2 3] [5 6] [8 9]]>)
Yet this works:
>(def t1 [[1 1] [2 2] [3 3]])
>(def t2 [[9] [9] [9]])
>(join-along 1 t2 t1)
[[9 1 1] [9 2 2] [9 3 3]]
If that could be figured out then it should simply be an issue of doing:
(* "A-updated-matrix" (pow (det A) (/ -1 (dimension-count A 0)))
Also I can imagine that the above is probably not the most efficient way of performing these matrix operations.
UPDATE:
So it appears to be a problem with the clojure accesses matrices, and outputting column vectors as row vectors.
E.g.
>(def a [[1 2 3] [4 5 6] [7 8 9]])
>(def t2 (get-column a 0)) ; Gets first column
>(join-along 1 t2 a)
Unidentified exception when trying to call procedure join-along with arguments (1 [1 4 7] [[1 2 3] [4 5 6] [7 8 9]])
However if we do
>(def i [[2] [3] [4]])
>(join-along 1 i a)
[[2 1 2 3] [3 4 5 6] [4 7 8 9]]
it works fine.
[1, 2, 3] & [2, 3, 4] gives us [2, 3] but how do you get the intersection of n arrays?
[[1, 2, 3], [2, 3, 4], [1, 3, 4]].something would give [3]
Looping with & works but there must be a better way.
[[1, 2, 3], [2, 3, 4], [1, 3, 4]].inject(:&) #=> [3]
Just & all arrays. Suppose you have 3 arrays.
a = [1,2,3]
b = [2,3,4]
c = [3,4,5]
a & b & c
=> [3]