(ns test.gadjett (:require [gadjett.linear :as glinear :refer [intersection-point-func linear-equation intersection-point find-below-and-above-y linear-equation-func highest-below-x linear-y linear-x-func log-x-intersection-point interpolate-linear-y linear-y-func intersection-point-from-2-lines-points lowest-above-x find-keys-with-value log-x-linear-y lowest-above-y log-x-linear-equation calc-interpolated-values linear-x interpolate-linear-x below-and-above-y highest-below-y find-keys-with-values-in]] [gadjett.collections :as gcoll :refer [compact unflatten-keys sequence->map sequence-of-maps->map =without-keys? dissoc-in split-by-predicate-positions mapify submap? positions filter-map vec->map assoc-cyclic infinity subsequence edn-zip fix-blank-lines map-nested-vals map-to-object deep-merge deep-merge-with mean map-object-kv flatten-keys flatten-keys* compactize-map compactize-map-recursive partition-between take-from-map map-with-index map-object-with-key deep-merge* range-till-end nearest-of-seq branches-and-leaves remove-ending-comments remove-blank-lines filter-branches out-of-bound? map-2d-vec split-by-predicate collify abs append-cyclic map-2d-vec-kv max-and-min index-of nearest-of-ss map-reverse-hierarchy map-object my-replace join-them]]))

Click here to make these examples interactive with ClojureScript.

gadjett.collections

=without-keys?

(=without-keys? obj-a obj-b keys-list)

Compare two maps exclusing some keys

  (=without-keys? {:a 1 :b 2 :c 3} {:a 1 :b 5} #{:b :c})

abs

(abs x)

Absolute value of a number

  (map abs (range -5 5))

almost=

(almost= x y)(almost= x y epsilon)

append-cyclic

(append-cyclic lst a)

Appends an element to a list popping out the first element.

  (-> (repeat 3 nil)
      (append-cyclic 1)
      (append-cyclic 2)
      (append-cyclic 3)
      (append-cyclic 4))

assoc-cyclic

(assoc-cyclic coll k v)(assoc-cyclic coll k v n)

Assoc a key-value pair to a map popping out an element of the map. If the key already exists, no element is popped out. If n is supplied, no elmement is popped out if the map has less than n entries.

  (-> {:a 1 :b 2 :c 3}
      (assoc-cyclic :d 4)
      (assoc-cyclic :e 5)
      (assoc-cyclic :f 6)
      (assoc-cyclic :g 7))

branches-and-leaves

(branches-and-leaves m)

Returns all branches and leaves off a nested map object.

(branches-and-leaves {:a {:b 1 :c {:d 2}} :e 3})

collify

(collify s)

Ensure s is a collection: if s is a collection returns it; otherwise returns (s)

(collify 1)
(collify [1 2 3])

compactize-map

(compactize-map m)

Removes entries with nil values.

  (compactize-map {:a 1 :b nil :c 3})

compactize-map-recursive

(compactize-map-recursive m)

Remove from a map the entries whose values are nil. If all the values of a nested map are nil the entrie is removed.


(compactize-map-recursive {:x 1 :z {:a nil} :a {:b nil :c 2 :d {:e nil :f 2}}})

deep-merge

(deep-merge & maps)

Deep merges maps.

(deep-merge {} {:a {:b 1}, :c {:e 4, :d 2, :f {:g 8}}} {:a {:b 1}, :c {:e 4, :d 2000, :f {:g 9000}}})

deep-merge-with

(deep-merge-with g & maps)

Like merge-with but deep.

(deep-merge-with concat
                 {:x {:b [1]
                      :a [1]}}
                 {:x {:a [3 4]}})

dissoc-in

(dissoc-in m [k & ks :as keys])

Dissociates an entry from a nested associative structure returning a new nested structure. keys is a sequence of keys. Any empty maps that result will not be present in the new structure. See assoc-in

  (dissoc-in {:a 1 :b 2} [:b])
  (dissoc-in {:a {:b 2 :B 3} :c 3} [:a :b])
  (dissoc-in {:a {:b 2} :c 3} [:a :b])

edn-zip

(edn-zip root)

A zipper for edn.

  (edn-zip {:a {:b 1}, :c {:e 4, :d 2, :f {:g 8}}})

filter-branches

(filter-branches m p)

Filters branches of a (nested) map m according to a predicate m.

(filter-branches {:x {:id 19 :b 1 :c {:id 2}} :e 3} :id)

filter-map

(filter-map f m)

Run a function on the values of a map and keep only the (key, value) pairs for which the function returns true

  (filter-map even? {:a 1 :b 2 :c 3})

fix-blank-lines

(fix-blank-lines s)

Removes blank lines from the begining and from the end (not from the middle)

  ; we use (char 10) for end-of-line due to technical issues with string manipulation with `codox`
  (let [lines (clojure.string/join (char 10) ["  ", "aa", "  ", "bb", " 	  "])]
  (fix-blank-lines lines))

flatten-keys

(flatten-keys m)

Flatten the keys of a nested map. Thanks to Jay Fields

(flatten-keys {:a {:b 1} :c {:d 2 :e 4 :f {:g 8}}})

index-of

(index-of s element)

Returns the index of an element in a sequence or -1 if not present.

(index-of (range 100) 18)

infinity

join-them

(join-them fns colls)

Join a sequence of collections colls according to function equality. fns - a sequence of functions colls - a sequence of collections

(let [a [{:id 1 :price 19} {:id 2 :price 3}]
        b [{:guid 1 :quantity 13}]]
     (join-them [:id :guid] [a b]))

map-2d-vec

(map-2d-vec f m)

Maps the values of a 2D vector where each element of the vector is a key-value pair. f is a 1-ary function that receives the key.

  (map-2d-vec inc [[:a 1] [:b 2]])

map-2d-vec-kv

(map-2d-vec-kv fk fv m)

Maps the values of a 2D vector where each element of the vector is a key-value pair. fk is a 1-ary function that receives the key. fv is a 1-ary function that receives the value.

    (map-2d-vec-kv name inc [[:a 1] [:b 2]])

map-nested-vals

(map-nested-vals f m)

Map the values of a nested map.

  (map-nested-vals first {:a [1 2 3]
                          :b {:c [4 5 6]}})

map-object

(map-object f m)

Returns a map with the same keys as m and with the values transformed by f. f is a 1-ary function that receives the key.

  (map-object inc {:a 1 :b 2 :c 3})

map-object-kv

(map-object-kv fk fv m)

Returns a map with the keys mapped by fk and the values mapped by fv.

    (map-object-kv name inc {:a 1 :b 2 :c 3})

map-object-with-key

(map-object-with-key f m)

Returns a map with the same keys as m and with the values transformed by f. f must be a 2-ary function that receives the key and the value as arguments.

  (map-object-with-key list {:a 1 :b 2 :c 3})

map-reverse-hierarchy

(map-reverse-hierarchy m)

Turns a hash map inside out. See: here

  (map-reverse-hierarchy {:monday {:banana 2 :apple 3} 
                          :tuesday {:banana 5 :orange 2}})

map-to-object

(map-to-object f lst)

Returns a map whose keys are the elements of lst and values are mapped by f.

  (map-to-object inc (range 5))

map-with-index

(map-with-index s idx-key val-key)

Maps a sequence to a sequence of maps with index and value

      (map-with-index [10 20 30] :idx :val)

mapify

(mapify f s)

Takes a seq, and returns a map where the keys are the result of applying f to the elements in the seq. The result of f should be unique for each element in the seq, otherwise you will loose some data. If it is not unique, consider using group-by.

  (mapify inc (range 5) )

max-and-min

(max-and-min x)

Returns a couple of the max and the min of a sequence.

  (max-and-min (range 5))

mean

(mean x)

Calculates the mean (a.k.a average) of a sequence of numbers.

  (mean [1 2 10 -1 12.3])

my-replace

(my-replace smap form)

Recursively transforms form by replacing keys in smap with their values, spliced. The values in smap must be sequences. Like clojure.walk/prewalk-replace but supports list in values.

(my-replace '{go (go gadjett)} '(go (<! (timeout 100)) (go (<! timeout 0))))

nearest-of-seq

(nearest-of-seq a b)

Maps each element of b to its nearest element in a. If a is empty, returns b.

  (nearest-of-seq (range 5) [1.2 3.4 4])

nearest-of-ss

(nearest-of-ss ss x)

Returns the nearest number to x of a sorted set

  (nearest-of-ss (apply sorted-set (range 5)) 1.2)

out-of-bound?

(out-of-bound? v idx)

Checks if index idx is in range of vector v. More efficient than (get v idx)

    (map #(out-of-bound? [1 2 3] %) [-1 0 1 2 3 4])

partition-between

(partition-between pred coll)

Splits a collection between two items according to predicate pred - which means split the sequence on breaking point.

See: here

For instance, split each time the series stop being ascending:

(partition-between > [1 2 4 9 8 7 6 5 1 2 4 5 11])

positions

(positions coll-of-lengths & {:keys [max-val first-val], :or {max-val infinity, first-val 0}})

Receives a collection of lengths and returns a list of start and end positions. Options: * max-val: (default infinity) - max value for end * first-val: (default 0) - first value of start

  (positions '(10 10 20) :first-val 100 :max-val 137)

range-till-end

(range-till-end & args)

Like range but including the end.

  (range-till-end 10)
(range-till-end 10 18)
(range-till-end 10 100 5)

remove-blank-lines

(remove-blank-lines s)

Removes blank lines.

  ; we use (char 10) for end-of-line due to technical issues with string manipulation with `codox`
  (let [lines (clojure.string/join (char 10) ["  ", "aa", "  ", "bb", " 	  "])]
  (remove-blank-lines lines))

remove-ending-comments

(remove-ending-comments s)

Removes comment lines from the end.

  ; we use (char 10) for end-of-line due to technical issues with string manipulation with `codox`
  (let [lines (clojure.string/join (char 10) ["aa", "  ", "bb" "; this comment should not appear"])]
  (remove-ending-comments lines))

select-keys-in-order

(select-keys-in-order m keyseq)

Thanks Jay Fields

select-vals

(select-vals map keyseq)

select-vals-in-order

(select-vals-in-order map ks)

Thanks Jay Fields

sequence->map

(sequence->map s)

Converts a sequence into a map where the keys are the indexes of the elements in the sequence.

(sequence->map [10 20 30])

sequence-of-maps->map

(sequence-of-maps->map coll key-fn val-fn)

Converts a sequence of maps into a map where:

  • the keys are extracted from the maps using key-fn
  • the vals extracted from the maps using val-fn
(sequence-of-maps->map [{:key :price :value 19}
                        {:key :quantity :value 100}]
                        :key :value)

split-by-predicate

(split-by-predicate coll pred n)

Splits a collection to items where the separator is a repetition of at least n elements that satisfy pred.

Inspired by: this question.

  (split-by-predicate (shuffle (range 30)) even? 2)

split-by-predicate-positions

(split-by-predicate-positions coll pred n d)

Optimized version of split-by-predicate where we assume that the data is from a signal that we can sample.

Instead of checking each element, we check 1 over n elements.

We return the positions where the data splits.

  (let [data (map Math/sin (range 0 6.28 0.001))]
    (split-by-predicate-positions data #(<= -0.01 % 0.01) 2 10))

The following assertion holds:

  (= (split-by-predicate coll pred n)
     (map #(apply subsequence data %) (split-by-predicate-positions coll pred n 1)))

Here is an example:

  (let [data (map Math/sin (range 0 6.28 0.01))]
    (= (split-by-predicate data #(<= -0.01 % 0.01) 2)
       (map #(apply subsequence data %) (split-by-predicate-positions data #(<= -0.01 % 0.01) 2 1))))

submap?

(submap? m1 m2)

Checks if m1 is a submap of m2. Map m1 is a submap of m2 if all key/value pairs in m1 exist in m2.

  (submap? {:a 1} {:a 1 :b 2})
  (submap? {:a 1} {:a 1 :b 2 :c nil})

subsequence

(subsequence coll start end)

Returns a lazy subsequence of coll, starting at start, ending atend` (not included).

  (subsequence (range) 10 20)

substr

(substr s start)(substr s start end)

Like clojure.core/subs but prevents some exceptions when the start or end are out of bound.

  (subs "" -2)

take-from-map

(take-from-map n m)

Creates a map with n leaves which are nested values of m. The following assertion holds:

      (>= n (count (flatten-keys (take-from-map n m)))))))
  (take-from-map 3 {:a {:b 1}, :c {:e 4, :d 2, :f {:g 8}}})

unflatten-keys

(unflatten-keys m)

Unflattend the keys of a map that has been flatten-keysed.

(unflatten-keys {[:a :b] 1, [:c :d] 2, [:c :e] 4, [:c :f :g] 8})

vec->map

(vec->map vec)

Converts a 2d vec to a hash-map.

   (vec->map [[:a 1] [:b 2]])