listkotlinrangeintervals

Finding the most common interval in a list of doubles


I am currently stuck on evaluating a list of some Doubles representing time intervals. Let's say I have an unordered list of up to 100 values fluctuating around 1: [0.897, 0.912, ... 1.214, 0.981]

I am now trying to find the interval of 0.05s that includes the most values in my list (say 20 of a list with 100 values).
Below is what I came up on my own and although it seems to work on my dummy data, this approach (looping the entire list for every interval) appears really redundant to me, especially if I were to evaluate much larger lists.

I am interested if someone could advice a more elegant way, perhaps using plotting of some sort? ´´´

    var lowerEnd = 0.5
    var higherEnd = 1.5
    var numberOfElements = 0
    var currentMost = 0
    var mostCommonRange = 0.0

    while(lowerEnd < higherEnd) {
        records.forEach { entry ->
            if(lowerEnd <= entry && entry < (lowerEnd + 0.05)) {
                numberOfElements += 1
            }              
        }
        if(numberOfElements > currentMost) {
            currentMost = numberOfElements
            mostCommonRange = lowerEnd
        }
        numberOfElements = 0
        lowerEnd += .05
    }

´´´


Solution

  • Since you only consider ranges that start and end at multiples of 0.05 (and not e.g. 0.01 ~ 0.06), just doing (x / 0.05).toInt() will tell you which range a number x is in.

    So you just group by (x / 0.05).toInt(), and count how many items are in each group, then find the biggest group.

    fun rangeLowerBound(list: List<Double>) =
        list.groupingBy { (it / 0.05).toInt() }.eachCount().maxBy { it.value }.key * 0.05
    

    rangeLowerBound(listOf(-0.1, -0.11, -0.13, 0.1, 0.11, 0.12, 0.13)) will return 0.1, meaning that the range 0.1 ~ 0.15 contains the most numbers out of all the other ranges.

    Note that this assumes the list is non-empty. If the list can be empty, you can use .maxByOrNull { it.value }?.key?.times(0.05) and return that (which would be null if the list is empty), or provide a default value with ?:.