1
\$\begingroup\$
(defn ret-match-row
  "Finds a row in in-seqB that matches in-valA and in-seq-keyB"
  [in-valA in-seq-keyB in-seqB]
  (filter #(= in-valA (in-seq-keyB %1)) in-seqB))

I want to expand this function, so that it still must always accept one comparison key and that n more comparison keys could be passed to the function if need be.

The only way I can think of to do this is create a non # anonymous function that would handle the comparison of multiple arguments. I do not know Clojure macros well enough to know if this would be an appropriate place to use a macro.

Minimally I would rewrite the function's argument signature like this:

(defn ret-match-row
  "Finds a row in in-seqB that matches in-valA and other optional vals."
  [match-keyA in-seq-keyB in-seqB & optional-match-keys]

Any thoughts, pointers, or guidance would be appreciated.

Here is some dummied up real data (dummied up to protected sensitive information)

666/0010|RET|xyz-ab-caba|SMITH|JOHN|HEALTHCO|377.94|20140702|201407| 2014-07-01

I need to filter on the ssn field (xyz-...) and the health description as an AND condition. I've dummied up the health description as HEALTHCO, but, in reality, the health description includes words like SPOUSE, SINGLE, and so on and is much more robust.

\$\endgroup\$
2
  • \$\begingroup\$ Could you add example input/output? \$\endgroup\$
    – georgek
    Commented Aug 7, 2014 at 2:32
  • \$\begingroup\$ @georgek Added example in OP and edited. \$\endgroup\$ Commented Aug 7, 2014 at 12:30

1 Answer 1

1
\$\begingroup\$

If I'm understanding your question right, you want to write a function that will take a call like this:

(matching-entries entries :ssn "xyz-ab-caba" :health-desc "HEALTHCO")

and it will return a seq of entries with matching data for the given keys:

("666/0010|RET|xyz-ab-caba|SMITH|JOHN|HEALTHCO|377.94|20140702|201407| 2014-07-01")

(in this case, only one match was returned)

The most idiomatic syntax I can think of for a function like this would be something like this:

; notes: 
;
; 1) rows has to be the first argument, as everything after '&' is assumed to be 
;    a key-value combination
;
; 2) This is assuming that each row is represented as a map, so that you can easily
;    grab the value for a given comparison key. If your rows are simply strings,
;    then you'll need to convert them to maps first, perhaps by writing a helper 
;    function that splits the string on `|` and zips your comparison keys with the
;    data in each cell., e.g. (zipmap [:foo :bar :ssn ...] 
;                                     (clojure.string/split #"|" row))

(defn matching-entries [entries & queries]
  (letfn [(match? [entry]
            (every? (fn [[k v]] (= v (k entry))) 
                    (partition 2 queries)))]
    (filter match? entries)))

(partition 2 queries) takes arguments like :ssn "xyz-ab-caba" :fname "JOHN" and turns it into a list of key-value "queries", i.e. '((:ssn "xyz-ab-caba") (:fname "JOHN")). Then every? checks to make sure that each one of these queries is satisfied by a given entry. Finally, we use filter to find all the entries that have the desired values for the given keys.

\$\endgroup\$
1
  • \$\begingroup\$ Thanks. I'm taking a small holiday, but I'll try this out, and comment back. \$\endgroup\$ Commented Aug 9, 2014 at 11:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.