Clojure AND / OR of Sets - clojure

(defn GetValuesFromWhereCommand
"return a list of values from Where command"
[Query tableName]
(let [values (re-seq #"[0-9a-zA-Z_=<>]+" ((re-find #"WHERE(.*)" Query) 1))
bitwise (re-find #"AND|OR" Query)
tempList (ref #{})
]
; first loop will look for the operators = < >
(doseq [item values]
(let [result (case (re-find #"[=><]" item)
"=" (GetRowsfromCondition tableName item = )
"<" (GetRowsfromCondition tableName item < )
">" (GetRowsfromCondition tableName item > )
nil (println "nothing")
)]
(when (not= nil result) (dosync (alter tempList conj result)) )
tempList)
)
(println tempList)
tempList) ; get the Where from Update ','
)
here is my output.
#<Ref#5a4e229e: #{#<Ref#3fc2e163: #{0}> #<Ref#63280c85: #{0 1}>}>
i would like to make implement AND operation that will return #{0}
and OR that will return #{0 1}.
my problem is how to access the lists i have created. I wasn't able to use union/intersection for some reason.

You should deref all the inner sets and apply union to the new set
it should look somthing like this:
(let [newList (ref #{})] (doseq [item #your_ref_to_set_of_refs] (dosync (alter newList conj #item))) (apply union #newList))

Related

Lazy Sequence Clojure

I was trying to modify a vector of vector but ended up with lazy-seq inside. I am new to clojure. Can someone help me to get this correctly?
(require '[clojure.string :as str])
;;READ CUST.TXT
(def my_str(slurp "cust.txt"))
(defn esplit [x] (str/split x #"\|" ))
(def cust (vec (sort-by first (vec (map esplit (vec (str/split my_str #"\n")))))))
;;func to print
(for [i cust] (do (println (str (subs (str i) 2 3) ": [" (subs (str i) 5 (count (str i)))))))
;;CODE TO SEARCH CUST
(defn cust_find [x] (for [i cust :when (= (first i) x )] (do (nth i 1))))
(type (cust_find "2"))
;;READ PROD.TXT
(def my_str(slurp "prod.txt"))
(def prod (vec (sort-by first (vec (map esplit (vec (str/split my_str #"\n")))))))
;;func to print
(for [i prod] (do (println (str (subs (str i) 2 3) ": [" (subs (str i) 5 (count (str i)))))))
;;CODE TO SEARCH PROD
(defn prod_find [x y] (for [i prod :when (= (first i) x )] (nth i y)))
(prod_find "2" 1)
(def my_str(slurp "sales.txt"))
(def sales (vec (sort-by first (vec (map esplit (vec (str/split my_str #"\n")))))))
; (for [i (range(count sales))] (cust_find (nth (nth sales i) 1)))
; (defn fill_sales_1 [x]
; (assoc x 1
; (cust_find (nth x 1))))
; (def sales(map fill_sales_1 (sales)))
(def sales (vec (for [i (range(count sales))] (assoc (nth sales i) 1 (str (cust_find (nth (nth sales i) 1)))))))
; (for [i (range(count sales))] (assoc (nth sales i) 2 (str (prod_find (nth (nth sales i) 2) 1))))
(for [i sales] (println i))
When I print sales vector I get
[1 clojure.lang.LazySeq#10ae5ccd 1 3]
[2 clojure.lang.LazySeq#a5d0ddf9 2 3]
[3 clojure.lang.LazySeq#a5d0ddf9 1 1]
[4 clojure.lang.LazySeq#d80cb028 3 4]
If you need the text files I will upload them as well.
In Clojure, for and map, as well as other functions and macros working with sequences, generate a lazy sequence instead of a vector.
In the REPL, lazy sequences are usually fully computed when printing - to have it printed, it's enough to remove the str in your second to last line:
(def sales (vec (for [i (range(count sales))] (assoc (nth sales i) 1 (cust_find (nth (nth sales i) 1))))))
Just in case, note that your code can be prettified / simplified to convey the meaning better. For example, you are just iterating over a sequence of sales - you don't need to iterate over the indices and then get each item using nth:
(def sales
(vec (for [rec sales])
(assoc rec 1 (cust_find (nth rec 1)))))
Second, you can replace nth ... 1 with second - it will be easier to understand:
(def sales
(vec (for [rec sales])
(assoc rec 1 (cust_find (second rec))))
Or, alternatively, you can just use update instead of assoc:
(def sales
(vec (for [rec sales])
(update rec 1 cust_find)))
And, do you really need the outer vec here? You can do most of what you intend without it:
(def sales
(for [rec sales])
(update rec 1 cust_find))
Also, using underscores in Clojure function names is considered bad style: dashes (as in cust-find instead of cust_find) are easier to read and easier to type.
(for [i sales] (println (doall i)))
doall realizes a lazy sequence. Bare in mind that if the sequence is huge, you might not want to do this.

Clojure Dashboard query

I am trying to show a graph on riemann-dashboard using query
"pingDelay > 0" .
I already have indexed my data using following code
(let [index (index)]
(defn write-dht-metric [e]
(let [dhtstate (re-find #"dht_status: health\.(\S+), msg count (\d+) \((\d+) bytes\).*peak \{ping = (\d+)" (:pgmsg e))]
(if (not= dhtstate nil)
(do
(prn "RESULT>" dhtstate)
(index {:host "dht-info"
:service (:service e)
:time (unix-time)
:dhtStatus (get dhtstate 1)
:msgCount (get dhtstate 2)
:pingDelay (get dhtstate 3)}
)
)
)
)
)
)
However, I am not getting anything on graph. Earlier, I thought that perhaps its because my "pingDelay" is in string "12345", so, i also tried ":pingDelay #(Long. (get dhtstate 3))" without any success.
Can anyone please help me about what I must do to make it work?
Regards
defining top level forms in function calls is a little odd. It works only because defining a var returns that var to the calling form. It's more typical to write it like:
(defn write-dht-metric [e]
(let [dhtstate (re-find #"dht_status: health\.(\S+), msg count (\d+) \((\d+) bytes\).*peak \{ping = (\d+)" (:pgmsg e))]
(if (not= dhtstate nil)
(do
(prn "RESULT>" dhtstate)
(index {:host "dht-info"
:service (:service e)
:time (unix-time)
:dhtStatus (get dhtstate 1)
:msgCount (get dhtstate 2)
:pingDelay (get dhtstate 3)})))))
(let [index (index)]
(streams
write-dht-metric))
there are several other ways of writing it:
(defn write-dht-metric [e]
(let [dhstate (:dhstate e)]
(prn "RESULT>" dhtstate)
(index {:host "dht-info"
:service (:service e)
:time (unix-time)
:dhtStatus (get dhtstate 1)
:msgCount (get dhtstate 2)
:pingDelay (get dhtstate 3)})))
(let [index (index)]
(streams
(with :dhstate (re-find #"dht_status: health\.(\S+), msg count (\d+) \((\d+) bytes\).*peak \{ping = (\d+)" (:pgmsg event))
(when :dhstate
write-dht-metric)))
It turned out that I had to write value of my pingDelay in ":metric field". It starts working now.

Clojure closure not behaving as expected?

The repl returns 2 when expected to return 5.
(defn counter []
(let [count 1]
(fn []
(+ count 1)
)
)
)
(defn test-counter []
(let [increment (counter)]
(increment)
(increment)
(increment)
(increment)
)
)
count is not a mutable variable so (+ count 1) does not change its value. If you want mutation you can store the count in an atom and update it using swap!:
(defn counter []
(let [count (atom 0)]
(fn [] (swap! count inc))))

change struct-object state

I would like to change the state of the objects andre and blastoise, adding a new property(attribute/state) to the object... the name of this new property I want to add is "tax". I tryed the code below but didnt work out... help me plz:
(def andre {:owner "Andre" :type "car" :cur-speed 101 :license-plate "ABC"})
(def blastoise {:owner "Blastoise" :type "truck" :cur-speed 120 :license-plate "XYZ"})
(def car-tax[andre blastoise])
(defn calculate-car-tax [v]
(for [element v]
(if (> (element :cur-speed) 100) (dosync (alter element tax :20)))
)
)
(calculate-car-tax car-tax)
try
(assoc andre :tax 20)
From the docs:
user=> (doc assoc)
-------------------------
clojure.core/assoc
([map key val] [map key val & kvs])
assoc[iate]. When applied to a map, returns a new map of the
same (hashed/sorted) type, that contains the mapping of key(s) to
val(s). When applied to a vector, returns a new vector that
contains val at index. Note - index must be <= (count vector).
nil
user=>
Edit to include function:
(defn calculate-car-tax [v]
(for [element v]
(if (> (element :cur-speed) 100)
(dosync (assoc element :tax 20)))))

How can I find the difference in 2 data sets?

If I have 2 pipe delimited files containing bookmark data, for example. How can I read in the data then determine the difference in the two sets of data?
Input Set #1: bookmarks.csv
2|www.cnn.com|News|This is CNN
3|www.msnbc.com|Search|
4|news.ycombinator.com|News|Tech News
5|bing.com|Search|The contender
Input Set #2: bookmarks2.csv
1|www.google.com|Search|The King of Search
2|www.cnn.com|News|This is CNN
3|www.msnbc.com|Search|New Comment
4|news.ycombinator.com|News|Tech News
Output
Id #1 is missing in set #1
Id #5 is missing in set #2
Id #3 is different:
->www.msnbc.com|Search|
->www.msnbc.com|Search|New Comment
(use '[clojure.contrib str-utils duck-streams pprint]
'[clojure set])
(defn read-bookmarks [filename]
(apply hash-map
(mapcat #(re-split #"\|" % 2)
(read-lines filename))))
(defn diff-bookmarks [filename1 filename2]
(let [f1 (read-bookmarks filename1)
f2 (read-bookmarks filename2)
k1 (set (keys f1))
k2 (set (keys f2))
missing-in-1 (difference k2 k1)
missing-in-2 (difference k1 k2)
present-but-different (filter #(not= (f1 %) (f2 %))
(intersection k1 k2))]
(cl-format nil "~{Id #~a is missing in set #1~%~}~{Id #~a is missing in set #2~%~}~{~{Id #~a is different~% -> ~a~% -> ~a~%~}~}"
missing-in-1
missing-in-2
(map #(list % (f1 %) (f2 %))
present-but-different))))
(print (diff-bookmarks "bookmarks.csv" "bookmarks2.csv"))
Here is my stab at a functional-ish approach to the problem:
Create 2 maps, one for each file
Find the missing items between the two maps, using dissoc
Find the different, but shared items between the two maps, using intersection and filter
Code
(ns diffset
(:use [clojure.contrib.duck-streams]
[clojure.set]))
(def file1 "bookmarks.csv")
(def file2 "bookmarks2.csv")
(defn split-record [line]
"split line into (id, bookmark)"
(map #(apply str %)
(split-with #(not (= % \|)) line)))
(defn map-from-file [f]
"create initial map from file f"
(with-open [r (reader f)]
(doall (apply hash-map (apply concat (map split-record
(line-seq r)))))))
(defn missing [x y]
"return seq of all ids in x that are not in y"
(keys (apply dissoc x (keys y))))
(defn different [x y]
"return seq of all ids that match but have different bookmark string"
(let [match-keys (intersection (set (keys x)) (set (keys y)))]
(filter #(not (= (get x %)
(get y %)))
match-keys)))
(defn diff [file1 file2]
"print out differences between two bookmark files"
(let [[s1 s2] (map map-from-file [file1 file2])]
(dorun (map #(println (format "Id #%s is missing in set #1" %))
(missing s2 s1)))
(dorun (map #(println (format "Id #%s is missing in set #2" %))
(missing s1 s2)))
(dorun (map #(println (format "Id #%s is different:" %) "\n"
" ->" (get s1 %) "\n"
" ->" (get s2 %)) (different s1 s2)))))
Result
user> (use 'diffset)
nil
user> (diff file1 file2)
Id #1 is missing in set #1
Id #5 is missing in set #2
Id #3 is different:
-> |www.msnbc.com|Search|
-> |www.msnbc.com|Search|New Comment
nil
split them with re regexp and make a set out of them with (apply set (re-seq ... ) then call (difference set1 set2) to find the things that are in set 1 and not set 2. reverse it to find this items in set 2 that are not in set one.
look at http://clojure.org/data_structures for more info on clojure sets.
put the first data in a dictionary (hashtable) with the id as key
the read the next data line by line, retrieve the id from the hash.
if the id is not in the hash, output: id missing in set 1
if the value in the has differs, output: id is different
store the id's in a second hashtable
then run through the keys of the first hashtable
check if they are also in the second hashtable. if not output: id is missing in set2