Fork me on GitHub
#beginners
<
2018-09-26
>
quadron00:09:38

how do i make the api of a namespace directly accessible through another namespace?

seancorfield01:09:24

@veix.q5 There are various hacks and "here be dragons" libraries for doing that, but it's not generally considered good practice (if I'm understanding what you're asking).

seancorfield01:09:41

I think you're asking if there's a "standard" way for a namespace foo.bar to expose as (part of) its API some or all of the public functions from some other namespace (presumably that foo.bar uses)...?

enforser01:09:57

If I understand correctly, maybe Potemkin's import-vars would work for you. https://github.com/ztellman/potemkin#import-vars

โœ”๏ธ 4
seancorfield01:09:17

That's definitely in the "here be dragons" category ๐Ÿ™‚

quadron01:09:41

@seancorfield that's exactly what I meant

quadron01:09:20

so you mean I should avoid this altogether? It sure feels dangerous and hacky... I have two databases with the same interface as candidates, and I need to hide this choice for the time being

enforser02:09:37

I've only ever seen import-vars used in cases where someone just wanted to break a file up into different files due to size/complexity - but not to differentiate between different code paths. IMO it's fine to use it for code organization, but only if the functions being defined in the group of files are only accessed from the one file (where import-vars includes them).

enforser02:09:58

I'm curious what you mean by the same interface? They have the same functions available to them? Do the functions behave differently behind the scenes?

quadron02:09:47

datomic | datahike

quadron02:09:57

the functions look the same

seancorfield02:09:01

@veix.q5 Sounds like you might want to define a protocol and have one or more implementations of it -- that would be a non-hacky way of doing this.

๐Ÿ‘ 4
quadron02:09:37

huh! :thinking_face:

bamdad09:09:17

has anyone managed to use Apache CXF to setup a SOAP service with Clojure before ? ( I feel ashamed to asked about SOAP :-s )

dazld10:09:31

(defn foo [s] (-> s (clojure.string/trim) (fn [s] [s]))) throws a spec error, but I have no idea why

dazld10:09:47

(defn foo [s] (->> s (clojure.string/trim) (fn [s] [s]))) does not

dazld10:09:05

(repeated s isnโ€™t the issue)

dazld10:09:09

(defn foo [s] (-> s (clojure.string/trim) (fn [a] [a]))) also blows up

hiredman10:09:21

you should macro expand the -> and ->> forms

hiredman10:09:25

particularly, the question is: if (-> a (b)) = (a b) then (-> a (fn [])) = ?

dazld10:09:49

(-> a (b)) should be the same as (b a)

dazld10:09:10

(defn a [s] 
  (-> s
      (clojure.string/trim)
      (fn [other] other)))

dazld10:09:26

๐Ÿ’ฅ

hiredman10:09:34

sorry, it's 3:40am, yes (b a)

dazld10:09:40

go to bed ๐Ÿ˜‰

dazld10:09:45

my problem can wait!

dazld10:09:49

thank you though

hiredman10:09:50

so then what is (-> a (fn []))

hiredman10:09:10

macroexpanded, not evaluated

dazld10:09:23

thatโ€™s not what im doing in this case though

dazld10:09:27

Itโ€™s not an empty fn

hiredman10:09:35

doesn't matter

dazld10:09:38

Iโ€™m wrapping the argument in a vector and returning

bronsa10:09:40

that's not the problem, the empty fn is the minimal case

dazld10:09:55

also booms

hiredman10:09:59

run (macroexpand '(-> a (fn [])))

dazld10:09:10

(defn a [s] 
  (-> s
      (clojure.string/trim)
      (fn [_])))

dazld10:09:31

with macroexpand on the defn

dazld10:09:36

spec error

dazld10:09:45

the threading form on its own seems ok

dazld10:09:09

also boom

hiredman10:09:12

look at the macro expansion for the form I gave you, and note where the a ends up

stardiviner10:09:20

I don't understand why the (reduce concat ...) can't apply on doseq results?

hiredman10:09:04

-> and ->> are very simple syntactic transformations that don't understand semantics

๐Ÿ‘ 4
hiredman10:09:18

doseq by definition always returns nil

dazld10:09:56

itโ€™s for side effectful iteration, @stardiviner

dazld10:09:18

thanks for helping @hiredman

bronsa10:09:13

@stardiviner switch doseq to for

bronsa10:09:37

and you don't need the outer reduce concat either you can do it inline in for

bronsa10:09:02

(for [n (range ..) el (map .. ..)] el)

souenzzo12:09:42

Hey where I can find some beginner friendly material about reagent/cljs?

Charleshd13:09:41

@souenzzo the reagent tutorial is great if you haven't go through it yet : http://reagent-project.github.io/

jstaab17:09:00

Hey everyone, I've got some questions about clojurescript. I've been a clojure hobbyist for about 3 years now, but I've never had a chance to dive in. Now, I've got a possible opportunity coming up at work to start a project from scratch, and I'd really like to use clojure(script). What with jvm start up times, not knowing java, and having a strong background in javascript, I'm leaning toward going no-jvm if possible. I've been fiddling with the clojurescript compiler and lumo this morning, and (I hate to say it), I'm as frustrated as I have always been with clojure, which is to say, "somewhat". I really want to make this work, but documentation and blog posts on various topics are really sparse (coming from python/javascript) so when rough edges and magic crop up, I pretty much have to go straight to the source. What I'm dealing with right now is *command-line-args* working properly (prints [x]) when I run lumo src/cljs_playground/core.cljs x, but showing nil when I run lumo -c src build.cljs && node src/main.js x. What's the reason for this? How can I get it to work? I'm able to get arguments using process.argv, but they show up inconsistently between the two (the javascript file is argument #1 post-build). I'll attach my core.cljs and build.cljs.

jstaab17:09:04

Hold on, just discovered things...

jstaab17:09:52

Ok sorry, cljs-playground/core.cljs:

(ns cljs-playground.core
  (:require [cljs.nodejs :refer [process]]))

(enable-console-print!)

(println cljs.core/*command-line-args*)
(println (into [] (drop 2 (.-argv process))))

noisesmith17:09:01

lumo is useful, but the jvm implementation of the cljs compiler is definitely the standard. If you are using lumo remove java from your build toolchain, be sure that this is actually the expedient choice (java to build and pure js on deploy sometimes makes sense), and if it is, you'll likely find interop to node will be more reliable than cljs constructs

jstaab17:09:13

and build.cljs:

(require '[lumo.build.api :as b])

(b/build "src"
  {:main 'cljs-playground.core
   :output-to "out/main.js"
   :output-dir "out"
   :optimizations :advanced
   :target :nodejs
   :infer-externs true})

jstaab17:09:23

Hey @noisesmith, the main use case that I struggle with with the jvm is short-lived processes like command-line scripts. I know specific tools exist for them, but I was thinking if I could use cljs everywhere, I'd just learn one toolchain (based on something I know well), with a fast start-up time. Is there a story for developing command line applications on the jvm? My underlying frustration here has to do with the unix philosophy; clojure/the jvm don't seem to compose well in the small (though they're great in the large).

noisesmith17:09:11

I'm not talking about using java to run your tool, I'm talking about using it to compile your tool

noisesmith17:09:30

the java cljs compiler is the one that is officially maintained

jstaab17:09:36

Sure, so lumo to run, clojurescript compiler to build, node to run?

jstaab17:09:54

I had the same problems with the cljs compiler re: *command-line-args*

noisesmith17:09:56

you wouldn't even need lumo, you get a js file and node can run it

jstaab17:09:15

What would you do for a fast development feedback loop?

orestis20:09:42

Do note that shadow-cljs is probably the โ€œeasyโ€ tool that might be helpful to your use case. It supports Node scripts as first class and also nice npm integration. See #shadow-cljs for more.

jstaab17:09:35

I usually do something like find src | entr python main.py

noisesmith17:09:30

with a browser, figwheel gives a great incremental compilation / live reload experience, I'm not sure about anything that good with node though

noisesmith17:09:42

and yeah, that would be an advantage for lumo

jstaab17:09:03

ok, thanks

noisesmith17:09:08

figwheel can give you a cljs repl with fast feedback and auto-loading

noisesmith17:09:13

so that might be your best bet

dpsutton17:09:39

figwheel looks very promising because it is invoked almost (or the same?) as the regular cljs.main entry point

noisesmith17:09:49

in my experience live dev with figwheel is much nicer than with lumo

dpsutton17:09:10

figwheel main that is. if i were to start something completely new i would have ways to run my app with figwheel main and with cljs.main

noisesmith17:09:11

(but I only used it with a browser)

jstaab17:09:14

I've used figwheel for browser development before, and it was nice, although still magic to me so I struggled

jstaab17:09:37

Any existing full-stack cljs projects I could look at as an example?

dpsutton17:09:59

#figwheel-main is very helpful for when it gets to magicky. and somehow bruce is able to develop so much and also help out seemingly everyone with questions

jstaab17:09:06

Any idea what's going on with *command-line-args*? They're nil even if I use cljs compiler:

(ns cljs-playground.build
  (:require [cljs.build.api :as b]))

(defn -main [& args]
  (b/build "src"
    {:main 'cljs-playground.core
     :output-to "out/main.js"
     :output-dir "out"
     :optimizations :none
     :target :nodejs
     :infer-externs true}))

jstaab17:09:27

Building with clj -m cljs-playground.build

hiredman17:09:40

I don't really use clojurescript, but looking at the code it looks like command-line-args is only set via the code that launches a clojurescript repl

jstaab17:09:20

Oh, interesting

jstaab17:09:32

Well dang I guess I'm stuck with process.argv then?

jstaab17:09:07

Broader question (and I want to be clear that I'm not complaining, no one who maintains free software needs that): does this strike anyone else as broken? I would expect very little difference between two ways of running the same program, with the same tool, with the same config. The clojure ecosystem seems like it's full of this sort of thing. Is it just because it's a less mature ecosystem than javascript and python? Because there are so many smart people who work on/with clojure that this kind of thing has to be solved, and I must be missing something. Or is everyone so much smarter than me that I'm just left in the dust? Or maybe I've just forgotten what it feels like to learn something new.

noisesmith17:09:55

there are multiple compromises made where clojure / clojurescript chooses power and access to the lower layer it's implemented on over intuitive behavior

dadair17:09:31

My guess is that *command-line-args* is/was only meant at the time as a convenience for people using the REPL. Any other program can use the standard process.argv functinality.

hiredman17:09:37

I dunno, I like clojure a lot, but I am not very fond of clojurescript, in part because it seems like so many compromising decisions have been made there

hiredman17:09:48

I've been using clojure since before there was any language specific tooling for it (a coworker at my first clojure job start lein after he got frustrated with the maven multi-module build we had), and tooling in other languages (pip, npm) drives me nuts

jstaab17:09:18

I guess simple/easy is a real tradeoff

jstaab17:09:38

I've been debating whether to do this new project in elm, which is firmly in the easy camp (as far as build tooling goes)

sundarj17:09:54

Elm is nice, but it's browser-only, right? there's nothing for Node as far as i'm aware

jstaab18:09:21

Yeah, exactly, I lose the code-sharing aspect, which is something I value a lot with node/clojure

sundarj18:09:09

Elm also doesn't have proper interop with JS, which is a shame

sundarj18:09:13

on the other hand, PureScript and ClojureScript take interop seriously

jstaab18:09:09

I actually like elm's story for interop. You always have a very strong idea of which language you're working in, and you can freely use the proper idioms depending on where you are. The functional/immutable world of elm is so different from javascript's mutable/procedural conventions that it doesn't make sense to mash them together. Clojure obviously takes a different tack, which suits it equally well.

sundarj18:09:41

i was under the impression you could only interop with a limited subset of approved packages, which sort of defeats the purpose imo

jstaab18:09:39

Last I used it (about 2 years ago), that was the case for elm dependencies, but once you use a port to escape out to javascript, you're in weakly-typed mutable javascript land, complete with script tags etc. I had elm working well together with commonjs modules. If you're interested, my repo is here: https://github.com/staab/tetroggle-elm

sundarj18:09:25

ports do make sense from the purely-functional perspective i suppose, but i've never seen that as worthwhile, evidenced by my use of Clojure :p

sundarj18:09:15

for what it's worth, i only see Lein as magical. Boot and tools.deps are oriented around using Clojure to do your builds, which is my preference

jstaab18:09:17

It definitely seems like tools.deps is the way to go.

sundarj18:09:49

it's pretty great

seancorfield18:09:32

I think Elm's "port" approach to interop is very cool. It took a long time to evolve (I was part of the Elm community for quite a while during its early days -- I think Evan has done an incredible job with both Elm and its community and overall mindset!).

seancorfield18:09:17

Also, I'll +1 @U61HA86AGโ€™s comment about Boot/clj vs Leiningen in terms of "magic" ๐Ÿ™‚

sundarj18:09:52

oh yeah, for sure. Elm is a very well-designed language - i agree with many of Evan's choices in regards to it, just not all of them :~)

jstaab17:09:51

Thought I'd give clojure a real go of it

jstaab17:09:49

@hiredman do you think lein/boot/deps/cli are generally better than pip/npm or is it a familiarity thing? pipenv/pyenv are pretty ok, and I'm used to npm (webpack is the devil). Clojure tooling feels like a never-ending rabbit hole of magic to me, even though it has a lot of the positive characteristics of pip with virtual environments

jstaab17:09:18

Also, is deps/cli too bleeding edge to use on a new project? Should I stick with lein/boot? Any recommendations there?

Livnoor Brar18:09:02

apologies in advance.. This is out of context for the current discussion but a quick question... Has anyone tried reitit? It is a router library. (https://github.com/metosin/reitit) .. need some help in request-coercion.

sundarj18:09:01

@UC58KQH9A maybe try the #reitit channel?

Livnoor Brar09:09:01

Sure.. thanks a lot @U61HA86AG

johnj18:09:07

forget about lein/boot and just use tools.deps IMO

hiredman18:09:14

it doesn't matter, flip a 3 sided coin

hiredman18:09:53

I have some ancient version of lein on my laptop which still works great so I've never updated it

hiredman18:09:12

at work we use a pretty complicated boot build, but there is work underway to replace that with something clj based that is hopefully simpler

jstaab18:09:43

Great, thanks everyone. I think that's all my questions for now, I'll give tools.deps a shot and see where that goes

Denis G18:09:45

How can I efficiently take x numbers from lazy sequence without dropping them from very beginning. Meaning. e.g. Query is, get 5th and 10th fibonacci number. While taking 10th number, I donโ€™t want to recompute the 5 fibonacci terms, since I already have computed them, because I wanted to get the 5th term. Any solutions for this?

oscar18:09:49

When you drop, you are making a new sequence. Just keep around the old sequence and you won't recompute anything.

hiredman18:09:34

lazy seqs are caching

hiredman18:09:48

or memoized, or however you want to call it

Denis G18:09:06

so in my case I need to make (drop 4 lazy-s) then (take lazy-s), then (drop 5 (drop 4 lazy-s)), then take 1 again, right?

hiredman18:09:54

if you have a lazy seq of fibs, and want the 10th, why not use nth?

hiredman18:09:07

(nth fibs 10)

Denis G18:09:16

if n is 1000

Denis G18:09:17

like query

Denis G18:09:21

1000 and 2000

Denis G18:09:27

why to recompute first 1000 terms

hiredman18:09:56

it will only compute them if they haven't already been computed

hiredman18:09:12

lazy-seqs compute the value the first time they are realized

hiredman18:09:26

generally lazy-seqs of fibs are not smart

hiredman18:09:32

because of the caching

Denis G18:09:47

so if I define a lazy-fib as a func and call two times nth it should recompute the vals again

hiredman18:09:48

you will retain in memory every fib

hiredman18:09:02

if you don't build your fib lazy seq in such a way that you use the previous entries to compute the next, then you will do duplicate work though

Denis G18:09:55

perfect. exactly what I wanted to know

dpsutton18:09:24

There's also a closed form to compute Fibonacci numbers as well. Not sure if helpful here though

Denis G18:09:27

Itโ€™s again me solving some random hackerrank challenge. https://www.hackerrank.com/challenges/decibinary-numbers/problem?h_l=interview&amp;playlist_slugs%5B%5D=interview-preparation-kit&amp;playlist_slugs%5B%5D=dynamic-programming Here the point is that they need to compute some number sequence. Given k queries. I it was just an optimization I wanted to have in mind. Having 500th element. There is no need to compute nothing at all if query is for 200th or smth

hiredman18:09:16

nth definitely does

Denis G18:09:52

sorry. mixed val with coll ๐Ÿ˜… false alarm ๐Ÿ˜„

Mario C.19:09:07

I am using Boot to build a project. And in the from-lein task in the build.boot file there are commands to set environment variables. (set-env! :key "example value"). Are these environment variables only pertaining to the build process or are these also the application environment variables?

Mario C.19:09:36

Because in the dev box it doesn't look like that is the case.

Mario C.19:09:07

The environment variables I have set in my project.clj are not being processed at all. If I (println env) (Using environ) non of those the env variables are there.

Mario C.19:09:41

I know this is a long shot but I am pretty clueless right now

seancorfield19:09:38

Boot's set-env! affects the build process (only).

noisesmith19:09:52

no environment variable from build time will be in the production runtime unless you are generating something that sets the environment before starting the jvm - the jvm lacks the ability to portably set env vars after startup

seancorfield19:09:07

(I mean, if you run your code via Boot, I think it will take effect -- but that's not using a production artifact)

Mario C.19:09:22

In my project.clj I have :profiles {:dev {:env {:foo "bar"}}} and when I run my app locally via lein with-profile clj,dev run I can see the correct output of (println (get env :foo))

Mario C.19:09:56

But on the dev server those environments are not being picked up, for a lack of a better term.

Mario C.19:09:13

Where should I be looking at getting those environment variables set via the project.clj file?

noisesmith19:09:52

project.clj is a build tooling config, it's not meant to control runtime behavior of an app

noisesmith19:09:22

(you can use your build tool to run your app, but that's usually a bad idea)

Mario C.19:09:27

Where do you set your environment variables then?

noisesmith19:09:50

the same way you would set environment for any production task - usually via the run script or daemon config

noisesmith19:09:16

(or docker config, or tomcat container config or...)

noisesmith19:09:33

sometimes a shell script that sets a bunch of env vars then runs java on your uberjar suffices

noisesmith19:09:00

but most people have something more specialized, and often there's a separate ops team deciding how it needs to work

Mario C.19:09:46

Thanks @noisesmith @seancorfield, I guess I need to gain a little more understanding about all this

noisesmith20:09:09

@mario.cordova.862 a very simple script could look like this

#!/bin/sh                                                                       
                                                                                
export FOO='foo for prod'                                                       

JVM_OPTS='jvm opts for prod'                                                    

JAR='/path/to/uploaded.jar'                                                     
                                                                                
java $JVM_OPTS -jar $JAR
- the app would be able to see whatever value for FOO the script sets here

Mario C.20:09:45

So the env variables set in project.clj is really only for local development?

seancorfield20:09:51

Yes. Just to control the build or whatever else lein does directly for you.

seancorfield20:09:52

For example, when you run your project via lein with-profile clj,dev run. But once you've built an uberjar, lein is not involved so any env vars set by lein won't apply.

noisesmith20:09:41

and same goes for any other build tool - the configuration is there to make your artifact, and doesn't set the runtime config the artifact sees

noisesmith20:09:58

(unless you are configuring something that gets baked in while compiling of course)

Mario C.20:09:17

Thanks for clearing that up guys! I see the error in my reasoning now

awb9921:09:40

I have a vector that is ordered by

awb9921:09:00

I am trying to filter this vector. Fore each location I want to have for each algo the algo with the highest accuracy.

awb9921:09:12

Is it possible that I use a filter and the predicate of the filter internally is keeping a list location/algo combinations that were already used?

dadair21:09:26

Can you do a group-by :location first, then filter each groupโ€™s array, then flatten everything?

awb9921:09:58

for each group,

awb9921:09:17

I really would then have to create a group of algos,

awb9921:09:22

and then take the first.

awb9921:09:36

and all this making sure that the sort order does not get losts.

awb9921:09:49

In filtering sometimes I foudn that the order gets lost.

awb9921:09:16

This solution is sort of what I would do in my old imperative style.

wekempf21:09:16

No, filtering will never change the order.

dadair21:09:41

group-by (juxt :location :algo) to get map from [<location> <algo>] [..]?

juxt 4
๐Ÿ‘ 4
oscar21:09:08

If ordering is important, I would use reduce.

wekempf21:09:06

Yes, group-by can certainly cause reordering. Using reduce might be a bit complicated, though.

hiredman21:09:15

user=> (doc group-by)
-------------------------
clojure.core/group-by
([f coll])
  Returns a map of the elements of coll keyed by the result of
  f on each element. The value at each key will be a vector of the
  corresponding elements, in the order they appeared in coll.
nil
user=> 

awb9921:09:03

or my other idea was I first create a list of all location/algos,

hiredman21:09:06

you want two things, not one thing

wekempf21:09:08

Yes... but the groups themselves won't be ordered, so once you flatten...

awb9921:09:22

and then I do for each of this groups a "some"

awb9921:09:48

And my last idea was that I somehow process the list sequentially, and when I add a new element to the new vector, then I check if I already have a element with a prediccate

awb9921:09:49

I think the problem is really simple,

awb9921:09:00

for each group that is defined in a predicate,

awb9921:09:09

take the first element in the list.

awb9921:09:59

(map #(some algo-predicate %) (group-by group-predicate) )

awb9921:09:43

But still, there are so many functions in clojure, I thought I can do it easier and more elegant.

wekempf21:09:50

As long as order doesn't matter, yes, that's the way to do it.

awb9921:09:03

the order does matter...

jaihindhreddy-duplicate21:09:17

@bill.kempf group-by does not change the order

wekempf21:09:23

From the group-by doc... it creates a map, which isn't ordered.

wekempf21:09:35

The items in the groups are ordered, the groups are not.

wekempf21:09:45

So that algo won't be ordered.

noisesmith21:09:13

the items in each group are ordered by the order in the original input though

wekempf21:09:44

Yes, the items in the group are... but he's going to pull out single items from each group, and the groups are not ordered, so the end result isn't ordered.

awb9921:09:24

then it seems to me that a functional approahc is more complicated than an imperative approach for this problem ๐Ÿ˜ž

wekempf21:09:04

Harder to think about, maybe, but the final result I bet is better than the imperative approach.

Digital Baboon21:09:51

How does one get data out of a #object[Promise [object Promise]]? Into a vector, for example? Any example I've tried thus far ends with the exact same thing printed in my console ๐Ÿ˜ž

noisesmith21:09:26

is this in cljs?

noisesmith21:09:13

in cljs a Promise is a js object representing a value that will be available later, and you can chain a callback onto it to be called when the value is available

wekempf21:09:17

So, you need an implementation of a group-by that produces an array-map instead of a map. Then the algo works.

awb9921:09:49

@bill.kempf yes. that is a good idea!

wekempf21:09:37

And in the end, the functional approach beats the imperative ๐Ÿ˜‰

wekempf21:09:37

Actually... with this idea it should be fairly easy to implement this with reduce.

wekempf21:09:50

I've not looked at how group-by is implemented in closure, but it's easy enough to implement it using reduce. You could combine some steps so you don't need to implement a "stable-group-by".

noisesmith21:09:43

in clojure, reduce is the idiomatic way to do an imperative algorithm that consumes a collection in order while building arbitrary results

wekempf21:09:07

Yes, and reduce can be used to produce another list, and thus can be used to implement filter. Or it can produce a map, and thus can be used to implement group-by.

wekempf21:09:29

It's all the sequence monad. Everything can be built from the bind function out.

awb9921:09:04

thatnks guys! I will read some tutorials on advanced reduce use cases...

Denis G21:09:40

how to make a version of conj, that returns coll if val is nil, else conj, but without if else, like with using of fnil, but dunno how

jaihindhreddy-duplicate22:09:28

@hoertlehner (source group-by) gives us the implementation of group-by

(defn group-by 
  "Returns a map of the elements of coll keyed by the result of
  f on each element. The value at each key will be a vector of the
  corresponding elements, in the order they appeared in coll."
  {:added "1.2"
   :static true}
  [f coll]  
  (persistent!
   (reduce
    (fn [ret x]
      (let [k (f x)]
        (assoc! ret k (conj (get ret k []) x))))
    (transient {}) coll)))
Replacing the {} with (array-map) should do the expected. So ordered-group-by would be
(defn ordered-group-by 
  "Returns an array-map of the elements of coll keyed by the result of
  f on each element. The value at each key will be a vector of the
  corresponding elements, in the order they appeared in coll."
  [f coll]
  (persistent!
   (reduce
    (fn [ret x]
      (let [k (f x)]
        (assoc! ret k (conj (get ret k []) x))))
    (transient (array-map)) coll)))
Assuming your original vector is v, the solution now becomes
(->> v
  (ordered-group-by (juxt :location :algo))
  (mapv (fn [[[location algo] trials]]
          (assoc (apply max-key :accuracy trials)
            :location location
            :algo algo))))

jaihindhreddy-duplicate22:09:24

@hoertlehner Nevermind here is a counterexample to my solution

(def v [{:location "a" :algo "lqs1" :algo-params { :x 34 :y 34} :accuracy 1 :comment "remove this"}
   {:location "a" :algo "nn1"  :algo-params  { :x 34 :y 34} :accuracy 3}
   {:location "b" :algo "lqs1" :algo-params { :x 34 :y 34} :accuracy 5}
   {:location "a" :algo "lqs1" :algo-params { :x 4 :y 20} :accuracy 999}
   {:location "a" :algo "nn1" :algo-params { :x 34 :y 34} :accuracy 1 :comment "remove this"}
   {:location "b" :algo "nn1"  :algo-params  { :x 34 :y 34} :accuracy 3}
   {:location "b" :algo "lqs1" :algo-params { :x 4 :y 20} :accuracy 2 :comment "remove this"}
   {:location "b" :algo "nn1" :algo-params { :x 34 :y 34} :accuracy 1 :comment "remove this"}
  ])
You can assoc in the index of each record into it, then use group-by then get the max values with max-key, sort-by the index then dissoc the index out of all the records.

jaihindhreddy-duplicate22:09:54

This is what I ended up with:

(->> v
  (map-indexed #(assoc %2 :index %1))
  (group-by (juxt :location :algo))
  (mapv (fn [[[location algo] trials]]
          (assoc (apply max-key :accuracy trials)
            :location location
            :algo algo)))
  (sort-by :index)
  (mapv #(dissoc % :index)))
3:45 AM here. Time to sleep ๐Ÿ˜…

awb9910:09:41

beautiful solution! many thanks!!!