If I have a list of `data class Foo(val bar: Strin...
# getting-started
d
If I have a list of
data class Foo(val bar: String, val baz: Int)
and I want to only have a list with a unique
bar
with the max
baz
. Say [0] -> bar = "one", baz = 1 and [1] -> bar = "one", baz = 2, the resulting list should be in the same order and only contain [2]... how do I do this in the most concise and efficient way?
t
listOf(Foo("a",1), Foo("a", 2), Foo("b",1)).groupBy{it.bar} would create a Map<String, List<Foo>> where the keys are the different bar's en the values are all the Foo's that have that key (in order), you can then do a .map{it.baz}.max() on those values
d
you can then do a .map{it.baz}.max() on those values
I need a list of Foo, not a list of bars... And groupBy creates an intermediary map that I would have rathered to avoid...
t
Or is it that you want it like this: listOf(Foo("a",1), Foo("a", 2), Foo("b",1), Foo("a",3)) to be listOf(Foo("b",1), Foo("a",3)) ?
๐Ÿ‘๐Ÿผ 1
I can think of a way to do it, but not sure if its the best solution, might be something for #advent-of-code ๐Ÿคฃ (as in, .filterIndexed{ index, element -> ...} could work to filter the value away if there is an element with the same barand a higher biz later..
d
Yeah... I guess I'll have to do a regular loop through the elements and have a temporary map of bars and bazes to check against... I thought the standard library would have something for this... but I guess not.
Actually, maybe not so efficient, but
groupBy { it.baz }.mapValues { it.value.maxBy { foo -> foo.bar } }
, could probably do the trick...
Then I'd just get
.values
from the map...
t
Thats kinda what I suggested ๐Ÿ˜›
But maxing on bar is maybe not what you want
d
Why?
t
in your question you say you want to have a list of Foo's with distinct bar, and that Foo should have the highest baz out of all those Foo's if i understand the question
So grouping by bar and maxing on baz sounds a bit more logical then
d
๐Ÿ˜Š Yeah, got them mixed up... in my real code I got them right though...! Thanks for the help!
t
No worries ๐Ÿ™‚ happy I could help, groupBy is a really good language feature ๐Ÿ™‚
k
Instead of using
mapValues
followed by
values
you can use
map
which avoids creating a second intermediate Map:
Copy code
groupBy { it.bar }.map { it.value.maxBy(Foo::baz) }
Also, on the JVM only, the following avoids creating an intermediate map of Lists, of Foos but instead creates a Map of Foos directly:
Copy code
fold(LinkedHashMap<String, Foo>()) { map, foo ->
    map.merge(foo.bar, foo, maxBy(comparingInt(Foo::baz)))
    map
}.values
(For whatever reason, Java's useful
Map.merge
function is not available in Kotlin's
MutableMap
itself, but only when it's a typealias of Java's Map.)
๐Ÿ‘๐Ÿผ 1
p
You can also use
groupingBy { it.bar }.reduce { _, a, b -> if(a.baz > b.baz) a else b }.values
๐Ÿ‘ 2
๐Ÿ‘๐Ÿผ 1