get combinations of vector elements - clojure

I just wander if there any reducer in clojure that can give the same result as the below function without using recursion
the function should take a vector and returns combinations of its items (e.g. giving [1 2 3] and returns ((1 2 3) (1 2) (1 3) (1) (2 3) (2) (3) []))
(def combinations
"creates combinations of items for example [1 2 3]
will generate ((1 2 3) (1 2) (1 3) (1) (2 3) (2) (3) [])"
(memoize (fn[items]
(if (empty? items) [[]]
(let [els (combinations (rest items))]
(concat (map #(cons (first items) %)els) els))))))

An alternative approach would be to use a Clojure math lib.
For leiningen project.clj add this-
[org.clojure/math.combinatorics "0.1.3"]
To use-
(ns example.core
(:require [clojure.math.combinatorics :as c]))
(c/subsets [1 2 3])
;;=> (() (1) (2) (3) (1 2) (1 3) (2 3) (1 2 3))
You can see the source code here for a recursion-less solution if don't want the lib.

Related

Easy way to change specific list item in list

In Clojure I want change specific item(list) in list with other.
Here is my structure:
(def myLis '((3 3) (5 5) (5 5)))
(def som '(4 4))
I want change second element in myLis with som.
Result in myLis is '((3 3) (4 4) (5 5))
This is basic example. I have few hundred items in myList.
I try assoc and update-in but this not work on list.
When I try with assoc and update:
(update-in myLis [1] som)
(assoc myLis 1 som)
(assoc-in myLis [1] som)
got error like that:
clojure.lang.PersistentList cannot be cast to clojure.lang.Associative
How can quick change nth element in this structure (list of lists).
As pointed out in the clojure bible (Clojure Programming):
Because [lists] are linked lists, they do not support efficient random
access; thus, nth on a list will run in linear time (as opposed to
constant time when used with vectors, arrays, and so on), and get does
not support lists at all because doing so would not align with get’s
objective of sublinear efficiency.
So in order to replace an element of a list you will have to traverse all the elements up to it, thus running longer the further your item is in the list, and rebuild the list with the elements before it, the new item and all the elements after it (rest). Alternatively, turn the list into a vector, use update-in and back into a list if you absolutely have to use lists.
However, if you can, it would be worth seeing if you can use sequences in your code rather than lists, and thus you can interchangeably use vectors or other abstractions that are more efficient for the processing you are performing over them.
A trivial function that would meet the basics of your requirement with lists however, is:
(defn list-update-in [l i x]
(let [newlist (take i l)
newlist (concat newlist (list x))
newlist (concat newlist (drop (+ 1 i) l))]
newlist))
user> (list-update-in '((1 2) (2 3) (3 4)) 1 '(8 9))
((1 2) (8 9) (3 4))
There's no out of bounds checks on this
Adding an additional answer using loop/recur to realign the OP's own solution to be more lisp like.
(defn list-update-in-recur [l i x]
(loop [new-data [] old-list l]
(if (seq old-list)
(if (= (count new-data) i)
(recur (conj new-data x) (rest old-list))
(recur (conj new-data (first old-list)) (rest old-list)))
(apply list new-data))))
user> (list-update-in-recur '((1 2) (2 3) (3 4)) 1 '(8 9))
((1 2) (8 9) (3 4))
A few points to note:
It's written as a function, there are no 'def' values to set any global value. The final result is the return of the function (apply list new-data)
Arguments initialise the loop, the size of the growing list is used to determine if we want to replace the nth item or not (no index variables)
The passed in list becomes the initial old-list value which reduces in size each iteration, and the exit condition is simply if there are any more elements left in it using the test (seq old-list), which returns false/nil when it is empty.
Because we conj everything (which adds to start of the list) we reverse it to return the output. It now uses a vector to create the new sequence, and converts to a list as the last step instead of reversing a list
I've replaced nth with first and rest which are more efficient and don't have to traverse entire lists every iteration.
This is still very inefficient and only provided as a learning exercise.
You should normally use vectors like [1 2 3] in preference to lists like '(1 2 3) for most purposes. In Clojure, a list is normally used for a function call like (+ 1 2), while for data literals vectors normally used like [1 2 3].
Here is code showing 2 options that work.
Main code:
(ns clj.core
(:require
[tupelo.core :as t]
))
(t/refer-tupelo)
(def myLis [ [3 3] [5 5] [5 5] ] )
(def som [4 4] )
(spyx (assoc myLis 1 som))
(spyx (assoc-in myLis [1] som))
(defn -main [& args]
(println "-main"))
Result:
~/clj > lein run
(assoc myLis 1 som) => [[3 3] [4 4] [5 5]]
(assoc-in myLis [1] som) => [[3 3] [4 4] [5 5]]
You need this in project.clj to make the (spy ...) work:
:dependencies [
[tupelo "0.9.9"]
...
Update 2016-11-2:
If you really want to keep everything in a list, you can use replace-at from the Tupelo library. It works like this:
(def myLis '( (3 3) (5 5) (5 5) ) )
(def vec-1 [4 4] )
(def list-1 '(4 4) )
(spyx (t/replace-at myLis 1 vec-1 ))
(spyx (t/replace-at myLis 1 list-1))
(spyx (apply list (t/replace-at myLis 1 list-1)))
with result
> lein run
(t/replace-at myLis 1 vec-1) => [(3 3) [4 4] (5 5)]
(t/replace-at myLis 1 list-1) => [(3 3) (4 4) (5 5)]
(apply list (t/replace-at myLis 1 list-1)) => ((3 3) (4 4) (5 5))
The first 2 examples show that the new element can be anything, such as the vector [4 4] or the list (4 4). Also, notice that replace-at always returns a vector result. If you want the final result to be a list as well, you need to use (apply list <some-collection>).
My solution with lists:
(def newL '())
(def i 1)
(loop [k (- (count myLis) 1)]
(when (> k -1)
(cond
(= k i) (def newL (conj newL som))
:else (def newL (conj newL (nth myLis k)))
)
(recur (- k 1))
)
)

How do I replicate items from a list in Clojure?

I've tried this for so many nights that I've finally given up on myself. Seems like an extremely simple problem, but I guess I'm just not fully understanding Clojure as well as I should be (I partially attribute that to my almost sole experience with imperative languages). The problem is from hackerrank.com
Here is the problem:
Problem Statement
Given a list repeat each element of the list n times. The input and output
portions will be handled automatically by the grader.
Input Format
First line has integer S where S is the number of times you need to repeat
elements. After this there are X lines, each containing an integer. These are the
X elements of the array.
Output Format
Repeat each element of the original list S times. So you have to return
list/vector/array of S*X integers. The relative positions of the values should be
same as the original list provided as input.
Constraints
0<=X<=10
1<=S<=100
So, given:
2
1
2
3
Output:
1
1
2
2
3
3
I've tried:
(fn list-replicate [num list]
(println (reduce
(fn [element seq] (dotimes [n num] (conj seq element)))
[]
list))
)
But that just gives me an exception. I've tried so many other solutions, and this probably isn't one of my better ones, but it was the quickest one I could come up with to post something here.
(defn list-replicate [num list]
(mapcat (partial repeat num) list))
(doseq [x (list-replicate 2 [1 2 3])]
(println x))
;; output:
1
1
2
2
3
3
The previous answer is short and it works, but it is very "compressed" and is not easy for new people to learn. I would do it in a simpler and more obvious way.
First, look at the repeat function:
user=> (doc repeat)
-------------------------
clojure.core/repeat
([x] [n x])
Returns a lazy (infinite!, or length n if supplied) sequence of xs.
user=> (repeat 3 5)
(5 5 5)
So we see how to easily repeat something N times.
What if we run (repeat n ...) on each element of the list?
(def N 2)
(def xvals [1 2 3] )
(for [curr-x xvals]
(repeat N curr-x))
;=> ((1 1) (2 2) (3 3))
So we are getting close, but we have a list-of-lists for output. How to fix? The simplest way is to just use the flatten function:
(flatten
(for [curr-x xvals]
(repeat N curr-x)))
;=> (1 1 2 2 3 3)
Note that both repeat and for are lazy functions, which I prefer to avoid unless I really need them. Also, I usually prefer to store my linear collections in a concrete vector, instead of a generic "seq" type. For these reasons, I include an extra step of forcing the results into a single (eagar) vector for the final product:
(defn list-replicate [num-rep orig-list]
(into []
(flatten
(for [curr-elem xvals]
(repeat N curr-elem)))))
(list-replicate N xvals)
;=> [1 1 2 2 3 3]
I would suggest building onto Alan's solution and instead of flatten use concat as this will preserve the structure of the data in case you have input sth like this [[1 2] [3 4]].
((fn [coll] (apply concat (for [x coll] (repeat 2 x)))) [[1 2] [3 4]])
output: => ([1 2] [1 2] [3 4] [3 4])
unlike with flatten, which does the following
((fn [coll] (flatten (for [x coll] (repeat 2 x)))) [[1 2] [3 4]])
output: => (1 2 1 2 3 4 3 4)
as for simple lists e.g. '(1 2 3), it works the same:
((fn [coll] (apply concat (for [x coll] (repeat 2 x)))) '(1 2 3))
output => (1 1 2 2 3 3)
(reduce #(count (map println (repeat %1 %2))) num list)

clojure - combine to structures to get flatter result

I am trying to combine 2 structures:
(def acc [[1]])
and
(def pairs '((2 4)))
I want the following result:
'((1 2) (1 4))
I have tried the following:
(map-indexed
(fn [idx pair]
(map (fn [itm]
(concat (nth acc idx) (vector itm))) pair)) pairs)
But this gives:
(((1 2) (1 4)))
I could call first but this falls apart as bigger lists are attempted.
For example if I had
(def acc '((1 2) (1 4)))
and
(def pairs '((5 1) (1 4)))
I want to the result to be:
'((1 2 5) (1 2 1) (1 4 1) (1 4 4))
You want an algorithm that takes two input sequences of sequences and does this:
Take one sequence from each input sequence so that you have two sequences, s1 and s2
For each elem in s2 produce a sequence of s1 with elem appended to it
Repeat 1. until one of the two input sequences has no more sequences left
In Clojure:
(mapcat (fn [s1 s2]
(map (fn [elem]
(conj s1 elem)) s2))
acc pairs)
Note: your algorithm requires appending to collections - it is better to use a collection type that supports fast access to the back (like a vector)
(def acc '([1 2] [1 4])) ;; notice the inner collections are vectors
(def pairs '([5 1] [1 4]))
(defn zipp
[c1 c2]
(mapcat (fn [c3 c4]
(map (partial conj c3) c4)) ;; change this line for lists!
c1
c2))
(zipp acc pairs)
;; => ([1 2 5] [1 2 1] [1 4 1] [1 4 4])
If you must work with list's, you can change the line marked above to:
(map (partial conj (into [] c3)) c4))
It's rather ugly, IMO.
When mapping over nested data structures, for is often simpler.
user>
(defn unfolder
[acc pairs]
(for [combination (map list acc pairs)
tail (second combination)]
(conj (vec (first combination)) tail)))
#'user/unfolder
user> (unfolder '((1 2) (1 4)) '((5 1) (1 4)))
([1 2 5] [1 2 1] [1 4 1] [1 4 4])

In clojure, why doesn't "some" function work consistently on collections?

For below, why does the last one return a nil? Function "some" doesn't work on list of lists?
(some #(= % 1) '(1 3) ) ; ==> true
(some #(= % '(1 3)) ['(1 3) '(1 2 3)] ) ; ==> true
(some #(= % '(1 3)) '('(1 3) '(1 2 3)) ) ;==> nil
You should modify the expression like this:
(some #(= % '(1 3)) '((1 3) (1 2 3)) )
=> true
You already quoted the list by using ', you don't need to quote again in the quoted list.
You can easily check what happened in REPL:
user=> '((1 3) (1 2 3))
((1 3) (1 2 3))
user=> '('(1 3) '(1 2 3))
((quote (1 3)) (quote (1 2 3)))
#Kevin
I see #ntalbs answered but I am in the habit of testing various timings. You may be curious to note the time difference I observed:
(time (some #{'(1 3)} '((1 3) (1 2 3)))) ;0.073
(time (some #(= % '(1 3)) '((1 3) (1 2 3)))) ;0.632
(time (nil? (some #{'(1 3)} '((1 3) (1 2 3))))) ;0.068
(time (nil? (some #(= % '(1 3)) '((1 3) (1 2 3))))) ;0.628
If you are processing large amounts of data this may be a useful knowledge
As ntalbs points out, the issue here is double quoting. It may be a better idea to use vectors instead of lists, or build lists with list. Both would save you some confusion and vectors have different performance characteristics (near constant random access time).
(some #(= % '(1 3)) [[1 3] [1 2 3]])
(some #(= % '(1 3)) (list (list 1 3) (list 1 2 3)))

Need a similar function to disj but for a list in clojure. Is it overall possible?

I need to traverse a list and do some calculations with every element and the elements excluding that element. For example, having a list (1 2 3 1), I need pairs (1) (2 3 1), (2) (1 3 1), (3) (1 2 1) and (1) (2 3 1).
(...) with every element and the elements excluding that element.
With every element sounds like a map. Excluding that element sounds like a filter. Let's start with the latter.
user=> (filter #(not= % 1) '(1 2 3))
(2 3)
Great. Now let's try to map it over all elements.
user=> (let [coll '(1 2 3)] (map (fn [elem] (filter #(not= % elem) coll)) coll))
((2 3) (1 3) (1 2))
Creating actual pairs is left as an exercise for the reader. Hint: modify the closure used in map.
Keep in mind that the solution suggested above should work fine for short lists but it has a complexity of O(n²). Another issue is the fact that collections with duplicates aren't handled correctly.
Let's take a recursive approach instead. We'll base the recursion on loop and recur.
(defn pairs [coll]
(loop [ahead coll behind [] answer []]
(if (empty? ahead)
answer
(let [[current & remaining] ahead]
(recur remaining
(conj behind current)
(conj answer [(list current)
(concat behind remaining)]))))))
A trivial example:
user=> (pairs '(1 2 3))
[[(1) (2 3)] [(2) (1 3)] [(3) (1 2)]]
A vector with duplicates:
user=> (pairs [1 5 6 5])
[[(1) (5 6 5)] [(5) (1 6 5)] [(6) (1 5 5)] [(5) (1 5 6)]]
Seems a job for a list comprehension:
(defn gimme-pairs [coll]
(for [x coll]
[(list x) (remove #{x} coll)]))
user=> (gimme-pairs [1 2 3])
([(1) (2 3)] [(2) (1 3)] [(3) (1 2)])
I would actually skip creating a list for the single element, which would make the code even easier:
(defn gimme-pairs [coll]
(for [x coll]
[x (remove #{x} coll)]))
user=> (gimme-pairs [1 2 3])
([1 (2 3)] [2 (1 3)] [3 (1 2)])
If you need to keep duplicates then you can use an indexed collection:
(defn gimme-pairs [coll]
(let [indexed (map-indexed vector coll)
remove-index (partial map second)]
(for [[i x] indexed]
[x (remove-index (remove #{[i x]} indexed))])))
user=> (gimme-pairs [1 2 3 1])
([1 (2 3 1)] [2 (1 3 1)] [3 (1 2 1)] [1 (1 2 3)])
(def l [1 2 3])
(first (reduce (fn [[res ll] e]
[(conj res [(list e) (rest ll)])
(conj (vec (rest ll)) e)])
[[] l] l))
=> [[(1) (2 3)] [(2) (3 1)] [(3) (1 2)]]