Easy way to change specific list item in list - clojure

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))
)
)

Related

Concatenate elements to list by using loop in clojure?

I am trying to get into Lisps and FP by trying out the 99 problems.
Here is the problem statement (Problem 15)
Replicate the elements of a list a given number of times.
I have come up with the following code which simply returns an empty list []
I am unable to figure out why my code doesn't work and would really appreciate some help.
(defn replicateList "Replicates each element of the list n times" [l n]
(loop [initList l returnList []]
(if (empty? initList)
returnList
(let [[head & rest] initList]
(loop [x 0]
(when (< x n)
(conj returnList head)
(recur (inc x))))
(recur rest returnList)))))
(defn -main
"Main" []
(test/is (=
(replicateList [1 2] 2)
[1 1 2 2])
"Failed basic test")
)
copying my comment to answer:
this line: (conj returnList head) doesn't modify returnlist, rather it just drops the result in your case. You should restructure your program to pass the accumulated list further to the next iteration. But there are better ways to do this in clojure. Like (defn replicate-list [data times] (apply concat (repeat times data)))
If you still need the loop/recur version for educational reasons, i would go with this:
(defn replicate-list [data times]
(loop [[h & t :as input] data times times result []]
(if-not (pos? times)
result
(if (empty? input)
(recur data (dec times) result)
(recur t times (conj result h))))))
user> (replicate-list [1 2 3] 3)
;;=> [1 2 3 1 2 3 1 2 3]
user> (replicate-list [ ] 2)
;;=> []
user> (replicate-list [1 2 3] -1)
;;=> []
update
based on the clarified question, the simplest way to do this is
(defn replicate-list [data times]
(mapcat (partial repeat times) data))
user> (replicate-list [1 2 3] 3)
;;=> (1 1 1 2 2 2 3 3 3)
and the loop/recur variant:
(defn replicate-list [data times]
(loop [[h & t :as data] data n 0 res []]
(cond (empty? data) res
(>= n times) (recur t 0 res)
:else (recur data (inc n) (conj res h)))))
user> (replicate-list [1 2 3] 3)
;;=> [1 1 1 2 2 2 3 3 3]
user> (replicate-list [1 2 3] 0)
;;=> []
user> (replicate-list [] 10)
;;=> []
Here is a version based on the original post, with minimal modifications:
;; Based on the original version posted
(defn replicateList "Replicates each element of the list n times" [l n]
(loop [initList l returnList []]
(if (empty? initList)
returnList
(let [[head & rest] initList]
(recur
rest
(loop [inner-returnList returnList
x 0]
(if (< x n)
(recur (conj inner-returnList head) (inc x))
inner-returnList)))))))
Please keep in mind that Clojure is mainly a functional language, meaning that most functions produce their results as a new return value instead of updating in place. So, as pointed out in the comment, the line (conj returnList head) will not have an effect, because it's return value is ignored.
The above version works, but does not really take advantage of Clojure's sequence processing facilities. So here are two other suggestions for solving your problem:
;; Using lazy seqs and reduce
(defn replicateList2 [l n]
(reduce into [] (map #(take n (repeat %)) l)))
;; Yet another way using transducers
(defn replicateList3 [l n]
(transduce
(comp (map #(take n (repeat %)))
cat
)
conj
[]
l))
One thing is not clear about your question though: From your implementation, it looks like you want to create a new list where each element is repeated n times, e.g.
playground.replicate> (replicateList [1 2 3] 4)
[1 1 1 1 2 2 2 2 3 3 3 3]
But if you would instead like this result
playground.replicate> (replicateList [1 2 3] 4)
[1 2 3 1 2 3 1 2 3 1 2 3]
the answer to your question will be different.
If you want to learn idiomatic Clojure you should try to find a solution without such low level facilities as loop. Rather try to combine higher level functions like take, repeat, repeatedly. If you're feeling adventurous you might throw in laziness as well. Clojure's sequences are lazy, that is they get evaluated only when needed.
One example I came up with would be
(defn repeat-list-items [l n]
(lazy-seq
(when-let [s (seq l)]
(concat (repeat n (first l))
(repeat-list-items (next l) n)))))
Please also note the common naming with kebab-case
This seems to do what you want pretty well and works for an unlimited input (see the call (range) below), too:
experi.core> (def l [:a :b :c])
#'experi.core/
experi.core> (repeat-list-items l 2)
(:a :a :b :b :c :c)
experi.core> (repeat-list-items l 0)
()
experi.core> (repeat-list-items l 1)
(:a :b :c)
experi.core> (take 10 (drop 10000 (repeat-list-items (range) 4)))
(2500 2500 2500 2500 2501 2501 2501 2501 2502 2502)

Iteratively Construct Trie from a Tree

Introduction
The following function iteratively traverses a tree structure made of nested vectors. It tests each leaf against a predicate. The paths to all leaves which pass that truth-test are returned in a Trie structure. The later describes all found paths in a non-redundant way.
(defn get-trie-of-matches [is? tree]
(loop [[tree i path fk] [tree 0 [] nil]
accum {}]
(cond
(>= i (count tree)) ;; end of level / go up
(if (nil? fk) accum (recur fk accum))
(vector? (tree i)) ;; level down
(recur [(tree i) 0 (conj path i) [tree (inc i) path fk]] accum)
(is? (tree i)) ;; match
(let [new-accum (assoc-in accum (conj path i) {})]
(recur [tree (inc i) path fk] new-accum))
:else ;; next on same level
(recur [tree (inc i) path fk] accum))))
For further explanations see this post.
Example
Consider the following tree
(def tree [7 9 [7 5 3 [4 6 9] 9 3] 1 [2 7 9 9]])
Applied to the function, using even? as a predicate:
(get-trie-of-matches even? tree)
=> {2 {3 {0 {}, 1 {}}}, 4 {0 {}}}
The result describes the three paths to even numbers in tree. Namely 2-3-0, 2-3-1 and 4-0.
Problem
Even though the above function works, there might be better ways to construct the Trie while traversing the tree. At the moment a hash-map is flooded. On each match via assoc-in. The algorithm traverses the tree structure relatively from level to level but attaches each path in a global fashion to accum, which is not necessary. Also this method is only possible since a hashmap is used. It might anyways be better to use a sequential data-structure for the Trie in order to facilitate further iterations over it. This could not be adopted to the above method.
Question
How could a Trie be created from within the above function get-trie-of-matches without relying on hash-map specific 'global' 'write' functions?
I would propose to take a look at clojure's walk api.
It allows you to recursively apply some function to nested collections.
In this case you could use postwalk:
user> (require '[clojure.walk :as w])
user> (w/postwalk-demo [1 3 [4 [6] 7] [[8]]])
Walked: 1
Walked: 3
Walked: 4
Walked: 6
Walked: [6]
Walked: 7
Walked: [4 [6] 7]
Walked: 8
Walked: [8]
Walked: [[8]]
Walked: [1 3 [4 [6] 7] [[8]]]
[1 3 [4 [6] 7] [[8]]]
The key thing is you can replace any item at every step:
user> (w/postwalk #(if (coll? %) (reverse %) (inc %))
[1 3 [4 [6] 7] [[8]]])
(((9)) (8 (7) 5) 4 2)
Here we increment all the numbers, and reverse all the collections, keeping the nested structure.
Now applying to your task:
You could walk through your tree, keeping just even number's indices and not empty collections (e.g. collections containing even numbers, and not empty collections):
;; helper function
(defn empty-coll? [item]
(and (coll? item) (not (seq item))))
(defn make-trie [pred tree]
(w/postwalk
#(if (coll? %)
(keep-indexed (fn [idx item]
(cond (empty-coll? item) nil
(coll? item) (list idx item)
item idx
:else nil))
%)
(pred %))
tree))
in repl:
user> (def tree [7 9 [7 5 3 [4 6 9] 9 3] 1 [2 7 9 9]])
#'user/tree
user> (make-trie even? tree)
((2 ((3 (0 1)))) (4 (0)))
user> (make-trie #(> % 7) tree)
(1 (2 ((3 (2)) 4)) (4 (2 3)))
The structure is similar to your map. In fact you can produce any structure you want with minor changes to the function, for example your map structure:
(defn make-trie-map [pred tree]
(w/postwalk
#(if (coll? %)
(into {}
(keep-indexed (fn [idx item]
(cond (empty-coll? item) nil
(coll? item) {idx item}
item {idx {}}
:else nil))
%))
(pred %))
tree))
user> (make-trie-map even? tree)
{2 {3 {0 {}, 1 {}}}, 4 {0 {}}}

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 - 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])

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)]]