2

Let's have a class Player(val position: Int, val time: Float) and we want to sort an array or list of players by position. If some of these players have the same position after first sorting, we want to sort them by time in groups. By group I mean set of players with the same position.

I know about

list.sortedWith(compareBy<Foo> { it.a }.thenByDescending { it.b }.thenBy { it.c })

But of course it does not solve this case.

Is there any smart way in Kotlin to achieve this simple task? We can sort it manually by checking positions and swapping items, but I wonder if Kotlin has something to say in this case.

3
  • 1
    Why doesn't sortedWith solve this case? Commented Aug 27, 2017 at 14:18
  • 2
    You should make your question clearer: What kind of data structure do you have, do you want to have this one sorted always, i.e. whenever a new element is added it's supposed to be sorted in at the appropriate position or do you want to have a function which sorts on demand? What data structure do you need then? Commented Aug 27, 2017 at 14:54
  • yes, i wasn't specific about this. i wanted kotlin to showoff with case like this and converting array to map and then back to array is just not desired solution. i thought about some tricks like parallel sorting or even in place with some extra predicates, but you are right tho, we can sort it by converting list to map and then back again. i marked your answer correct. Commented Aug 28, 2017 at 9:01

1 Answer 1

3

You could first sort by position and time and then group by time with standard Kotlin functionality.

Example

data class Player(val position: Int, val time: Float)

val p1 = Player(1, 10f)
val plys = arrayOf(p1, p1.copy(position = 3),
        p1.copy(time = 0f), p1.copy(time = 20f),
        p1.copy(position = 2), p1.copy(position = 2, time = 20f))

val groupBy = plys.sortedWith(compareBy(Player::position, Player::time))
                  .groupBy { it.position }

Description

  1. sort the Array by the Player's position and time with sortedWith + compareBy
  2. group it by the Player's position

Result

The result is a Map<Int,List<Player>, which in the example looks like this:

    {
     1=[Player(position=1, time=0.0), Player(position=1, time=10.0), Player(position=1, time=20.0)], 
     2=[Player(position=2, time=10.0), Player(position=2, time=20.0)],
     3=[Player(position=3, time=10.0)]
    }
Sign up to request clarification or add additional context in comments.

3 Comments

thank you for your answer. I know about groupBy{}, but it results with a map instead of list as you wrote yourself. It changes structure of keeping players and in my case it is a deal breaker.
maps are easily converted to lists using toList() ... this should be marked the correct answer, or the OP should clarify the desired result
well it is not desired to sort an array through converting it to map and then back to array, but i wasn't specific about this, so i mark this answer correct

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.