OliverRadini
OliverRadini

Reputation: 6467

Using partials within function as value on a map

Firstly; sorry if the terminology I'm using is incorrect, I'm still very new to clojure and the paradigm shift is taking some time.

I am trying to work with a function which takes the first item from a set which is greater than twelve (is a 'teen' number). I can write this when I'm just applying it directly to a set, but I'm unsure how to write the function within a map. Can anyone point me in the right direction?

I tried a few things, typically along the lines of (partial (first (filter (partial < 12)))) but without any luck at all so far, and researching definitions of filter/partial has not yet proved fruitful.

TL/DR I want to have, as a value in a map, a function which takes the first item in a list which is greater than 12.

(def test-set [1, 8, 15, 22, 29])

(def some-functions {
  :first first
  :last last
  :teenth "I don't know what to put here"
})


(first (filter (partial < 12) test-set))

Upvotes: 0

Views: 90

Answers (2)

jomora
jomora

Reputation: 11

I found a small improvement to @jas' answer.

The functions

#(first (filter (partial < 12) %))

and

(defn teenth [coll] (first (filter (partial < 12) coll)))

use a combination of first and filter.

This is a use case for the some function as stated on clojuredocs.org [1].

I would propose to refactor the functions to

(fn [coll] (some #(if (< 12 %) %) coll))

and

(defn teenth [coll] (some #(if (< 12 %) %) coll))

Due to the slightly more complex predicate function #(if (< 12 %) %) we cannot use partial anymore.

Please be aware that you cannot create nested anonymous functions by using the reader macro #() [2]. In this case, you have to use fn to create the nested anonymous function as shown above.

Actually, you could use fn twice, but in my opinion it's not readable anymore:

(fn [coll] (some (fn [e] (if (< 12 e) e)) coll))

[1] https://clojuredocs.org/clojure.core/some#example-542692c6c026201cdc326940

[2] https://clojure.org/reference/reader#_dispatch

Upvotes: 1

jas
jas

Reputation: 10865

One way is to use an anonymous function when defining the map (https://riptutorial.com/clojure/example/15544/defining-anonymous-functions)

> (def some-functions {
  :first first
  :last last
  :teenth #(first (filter (partial < 12) %))})

> ((:first some-functions) test-set)
1

> ((:last some-functions) test-set)
29

> ((:teenth some-functions) test-set)
15

Of course you could also have explicitly defined your function and used it in your map:

> (defn teenth [coll] (first (filter (partial < 12) coll)))

> (def some-functions {
  :first first
  :last last
  :teenth teenth})

(As an aside, be careful with the word set. In clojure sets are unordered collections of unique values. https://clojure.org/reference/data_structures)

Upvotes: 1

Related Questions