I want to take a sequence [44 1 11] generated using (map #(nth %1 0 nil) v1) and feed (map) that into successive calls to the same function. I am just not sure which Clojure builtin or builtins to use other than for.
Here are the details.
Given these two vectors:
(def v1 [[44 2 3 4 5]
[1 6 7 5 10]
[11 12 13 14 15]])
(def v2 [[1 2 3 4 44]
[1 6 7 5 1]
[11 12 13 14 44]])
and this function
(defn ret-non-match-rows
"Expects a sequence of sequences, like what is returned from clojure-csv.
Returns all csv rows that do not match cmp-val at cmp-col-idx."
[s-o-s cmp-val cmp-col-idx]
(filter (complement nil?)
(map #(if (ret-col-match %1 cmp-val cmp-col-idx) nil %1) s-o-s) ))
So I am asking for help in how to feed (map) [44 1 11] into ret-non-match-rows like this
(ret-non-match-rows v2 44 4)
(ret-non-match-rows v2 44 1)
(ret-non-match-rows v2 44 11)
but using Clojure built-ins to generate those individual calls.
Thank You.
Edit:
The following gives me what I want, but I'm wondering if there is a cleaner way to do it.
(def ssn-1 [44 1 11])
(def tst (partial ret-non-match-rows v2 4))
(map #(tst %1) ssn-1)
I get back a sequence of sequences and will parse that to get my results.
Maybe you want this:
(map (partial ret-non-match-rows v2 44) (map first v1))
(assuming the 4 in the first example call is a typo and should be 44)
Related
I have a list of numbers 2 4 3 7 4 9 8 5 12 24 8.
I need to find numbers which are repeated more than once in clojure.
I have used frequencies function to find. But the result is
{2 1,4 2,3 1,7 1,9 1,8 2,5 1,12 1,24 1}
I intially thought of considering them as key value and then take each key value once and see if val is > 1. if value is greater than 1 then I need to inc 1.
But I am unable to work this out.
Can anyone please help me??
Is there anyway I can make this into [[2 1][4 2][3 1][7 1][9 1][8 2][5 1][12 1][24 1]] and consider each vector recursively or any better idea you can think of.
Thank you.
The function below will just continue on where you have stuck:
(defn find-duplicates [numbers]
(->> numbers
(frequencies)
(filter (fn [[k v]] (> v 1)))
(keys)))
It will filter map entries that have values greater than 1 and then extract their keys.
(find-duplicates [2 4 3 7 4 9 8 5 12 24 8])
;; => (4 8)
If you want the repeated items:
(defn repeated [coll]
(->> coll
frequencies
(remove #(= 1 (val %)))
keys))
(repeated [2 4 3 7 4 9 8 5 12 24 8])
;(4 8)
If you just want to count them:
(defn repeat-count [coll]
(->> coll
frequencies
(remove #(= 1 (val %)))
count))
(repeat-count [2 4 3 7 4 9 8 5 12 24 8])
;2
You can do it lazily, so that it will work on an endless sequence:
(defn repeated [coll]
((fn ff [seen xs]
(lazy-seq
(when-let [[y & ys] (seq xs)]
(case (seen y)
::several (ff seen ys)
::once (cons y (ff (assoc seen y ::several) ys))
(ff (assoc seen y ::once) ys)))))
{} coll))
(repeated [2 4 3 7 4 9 8 5 12 24 8])
;(4 8)
This is similar to core distinct.
... and finally, for brevity, ...
(defn repeated [coll]
(for [[k v] (frequencies coll) :when (not= v 1)] k))
I stole the use of keys from Piotrek Byzdyl's answer. It is only supposed to apply to a map. but works perfectly well here on a sequence of map-entries.
(->> s (group-by identity) (filter (comp next val)) keys)
You are on the right track.
If you seq over hash-map, e. g. via map, you get the kv tuple structure you described and can destructure an individual tuple in the element transformation function:
(->> s
(frequencies)
(map (fn [[number times]]
(cond-> number ; take number
(> times 1) (inc))))) ; inc if (times > 1), otherwise return number
You can use this approach.
(def c [2 4 3 7 4 9 8 5 12 24 8])
(->> c
sort
(partition-by identity)
(filter #(> (count %) 1))
(map first))
Clojure's map is what other lisps might call mapcar with car being roughly equivalent to clojure's first. This makes me wonder if there is a mapcdr and whether clojure has a such a function where cdr is roughly equivalent to clojure's rest.
I imagine the behavior to be like such:
(mapcdr #(apply + %) [1 2 3 4 5])
=> (15 14 12 9 5)
The expansion looking like:
(list (apply + [1 2 3 4 5])
(apply + [2 3 4 5])
(apply + [3 4 5])
(apply + [4 5])
(apply + [5])
You can use the fn reductions, which does almost what you want:
(->> [1 2 3 4 5]
reverse
(reductions +)
reverse)
Wrote something quick, though it'd still be nice to have something more native.
(defn maplist
"Based on Common Lisp's maplist."
[fn coll]
(if (empty? coll) nil
(cons (fn coll)
(maplist fn (rest coll)))))
(maplist #(apply + %) [1 2 3 4 5])
=> (15 14 12 9 5)
I'd be surprised if there isn't because it seems like standard map is just maplist with first wrapped around coll.
I making a poker hands game in clojure. I have to define a function such that such that it returns the ranks in the descending order. For example: order ["2H" "3S" "6C" "5D" "4D"] should return (6 5 4 3 2). But if there is a two-pair like this: ["5H" "AD" "5C" "7D" "AS"] then it should return (14 5 7), but mine returns [14 14 7 5 5], how can I correct this? It should work in the same way for other cases of poker hands as well like for a full house it should give the rank of the three of a kind and the rank of the two of a kind. So, for this I have written:
(defn order
[hand]
"Return a list of the ranks, sorted highest first"
(let [ranks (reverse (sort (map #(.indexOf "--23456789TJQKA" %)
(map #(str (first %)) hand))))]
(if (= ranks [14 5 4 3 2])
[5 4 3 2 1]
(into [] ranks))))
I have also written all the other poker hand functions like flush?, straight? etc.
Also, I have to define another function such that it takes two orders like '(8 5 9) '(8 7 3) and returns true if the first has the larger value of the first difference, else false. Could someone please give me an idea how to do this?
Updated to show sorting by count, then rank:
(defn ->r [hand]
(let [ranks (zipmap "23456789TJKQA" (range 2 15)) ; creates a map like {\2 2, .... \A 14}
count-then-rank
(fn [x y] (compare
[(second y) (first y)]
[(second x) (first x)]))]
(->> hand
(map (comp ranks first)) ; returns the rank for each card eg: '(5 14 5 7 14)
frequencies ; returns a map of rank vs count eg: {5 2, 14 2, 7 1}
(sort count-then-rank) ; becomes a sorted list of tuples eg: '([14 2] [5 2] [7 1])
(map first)))) ; extract the first value each time eg: '(14 5 7)
For a more complete solution, you can use the frequencies to determine if you have 4 of a kind, 3 of a kind, full house etc.
Updated with more info on straight and straight flush:
For a straight, one approach is:
Extract the ranks so you would have a list like '(14 3 2 4 5)
Sort this list to get '(2 3 4 5 14)
Get the first element: 2, and the last element 14
Construct a range from 2 (inclusive) to 15 (exclusive) to get '(2 3 4 5 6 7 8 9 10 11 12 13 14)
Compare against the sorted sequence. In this case the result is false.
Retry, but first replace 14 with 1.
replace => '(1 3 2 4 5)
sort => '(1 2 3 4 5)
(range 1 6) => '(1 2 3 4 5)
This time, the range and the sorted list match, so this is a straight.
(defn straight? [cards] ; eg: ["AH" "3H" "2H" "4H" "5H"]
(let [ranks (zipmap "23456789TJKQA" (range 2 15))
ranks-only (map (comp ranks first) cards) ; eg: '(14 3 2 4 5)
ace-high (sort ranks-only) ; eg: '(2 3 4 5 14)
ace-low (sort (replace {14 1} ranks-only)) ; eg: '(1 2 3 4 5)
consecutive #(= (range (first %) (inc (last %))) %)] ; eg: (= (range 1 6) '(1 2 3 4 5))
(or (consecutive ace-high)
(consecutive ace-low))))
For a flush, simply extract all the suits, and then ensure they are all equal:
(defn flush? [cards]
(apply = (map second cards))) ; this is when suit is the second character
Now, simply combine these two boolean conditions to determine if this is a straight flush
(defn straight-flush? [cards]
(and (straight? cards) (flush? cards)))
See if you can solve 4clojure best hand puzzle, to open up a large number of different ways to tackle this. When I solved this, I used similar, but not identical functions.
Spoiler a more complete solution (using suit first "D7" instead of rank first "7D") is below
https://github.com/toolkit/4clojure-solutions/blob/master/src/puzzle_solutions/best_hand.clj
I think frequencies will get you closer to what you're looking for.
user=> (frequencies [14 14 7 5 5])
{14 2, 7 1, 5 2}
You could use this for sorting:
user=> (sort-by (frequencies [14 14 7 5 5]) [14 14 7 5 5])
(7 14 14 5 5)
And then you could use distinct:
user=> (distinct [14 14 7 5 5])
(14 7 5)
Putting all of these together should get you exactly what you want. I'll leave that as an exercise for the reader. When I'm stuck wondering if there's an easy way to do something, I often turn to Clojure's cheatsheet.
I want to map over a sequence in order but want to carry an accumulator value forward, like in a reduce.
Example use case: Take a vector and return a running total, each value multiplied by two.
(defn map-with-accumulator
"Map over input but with an accumulator. func accepts [value accumulator] and returns [new-value new-accumulator]."
[func accumulator collection]
(if (empty? collection)
nil
(let [[this-value new-accumulator] (func (first collection) accumulator)]
(cons this-value (map-with-accumulator func new-accumulator (rest collection))))))
(defn double-running-sum
[value accumulator]
[(* 2 (+ value accumulator)) (+ value accumulator)])
Which gives
(prn (pr-str (map-with-accumulator double-running-sum 0 [1 2 3 4 5])))
>>> (2 6 12 20 30)
Another example to illustrate the generality, print running sum as stars and the original number. A slightly convoluted example, but demonstrates that I need to keep the running accumulator in the map function:
(defn stars [n] (apply str (take n (repeat \*))))
(defn stars-sum [value accumulator]
[[(stars (+ value accumulator)) value] (+ value accumulator)])
(prn (pr-str (map-with-accumulator stars-sum 0 [1 2 3 4 5])))
>>> (["*" 1] ["***" 2] ["******" 3] ["**********" 4] ["***************" 5])
This works fine, but I would expect this to be a common pattern, and for some kind of map-with-accumulator to exist in core. Does it?
You should look into reductions. For this specific case:
(reductions #(+ % (* 2 %2)) 2 (range 2 6))
produces
(2 6 12 20 30)
The general solution
The common pattern of a mapping that can depend on both an item and the accumulating sum of a sequence is captured by the function
(defn map-sigma [f s] (map f s (sigma s)))
where
(def sigma (partial reductions +))
... returns the sequence of accumulating sums of a sequence:
(sigma (repeat 12 1))
; (1 2 3 4 5 6 7 8 9 10 11 12)
(sigma [1 2 3 4 5])
; (1 3 6 10 15)
In the definition of map-sigma, f is a function of two arguments, the item followed by the accumulator.
The examples
In these terms, the first example can be expressed
(map-sigma (fn [_ x] (* 2 x)) [1 2 3 4 5])
; (2 6 12 20 30)
In this case, the mapping function ignores the item and depends only on the accumulator.
The second can be expressed
(map-sigma #(vector (stars %2) %1) [1 2 3 4 5])
; (["*" 1] ["***" 2] ["******" 3] ["**********" 4] ["***************" 5])
... where the mapping function depends on both the item and the accumulator.
There is no standard function like map-sigma.
General conclusions
Just because a pattern of computation is common does not imply that
it merits or requires its own standard function.
Lazy sequences and the sequence library are powerful enough to tease
apart many problems into clear function compositions.
Rewritten to be specific to the question posed.
Edited to accommodate the changed second example.
Reductions is the way to go as Diego mentioned however to your specific problem the following works
(map #(* % (inc %)) [1 2 3 4 5])
As mentioned you could use reductions:
(defn map-with-accumulator [f init-value collection]
(map first (reductions (fn [[_ accumulator] next-elem]
(f next-elem accumulator))
(f (first collection) init-value)
(rest collection))))
=> (map-with-accumulator double-running-sum 0 [1 2 3 4 5])
(2 6 12 20 30)
=> (map-with-accumulator stars-sum 0 [1 2 3 4 5])
("*" "***" "******" "**********" "***************")
It's only in case you want to keep the original requirements. Otherwise I'd prefer to decompose f into two separate functions and use Thumbnail's approach.
(def tmp = [ 1 2 3 9 4 8])
I'm trying to create pairs of 2, then for each pair, subtract the second number from the first.
desired result: (1 6 4)
Here is what I was trying:
(map #(apply - %2 %1) (partition 2 tmp))
how can I do this?
Partition produces a sequence of sequences so the function you map over them needs to expect a sequence of two items. There are several ways to express this:
(def tmp [ 1 2 3 9 4 8])
user> (map #(- (second %) (first %)) (partition-all 2 tmp ))
(1 6 4)
user> (map #(apply - (reverse %)) (partition-all 2 tmp ))
(1 6 4)
user> (map (fn [[small large]] (- large small)) (partition-all 2 tmp ))
(1 6 4)
The version using apply is different because it will still "work" on odd length lists:
user> (map #(apply - (reverse %)) (partition-all 2 [1 2 3 4 5 6 7] ))
(1 1 1 -7)
The others will crash on invalid input, which you may prefer.
Here's a solution using reduce
(reduce #(conj %1 (apply - (reverse %2))) [] (partition-all 2 [1 2 3 9 4 8]))
=> [1 6 4]
I wonder why this solution was overlooked...
Since switching the order of subtraction is simply the negative of the original subtraction, (a-b=-(b-a)),
the solution becomes more efficient (only in this particular case!!)
(map #(- (apply - %)) (partition-all 2 [1 2 3 9 4 8]))
Pedagogically, Arthur's solution is correct. This is just a solution that is more suited the specfic question.