代码之家  ›  专栏  ›  技术社区  ›  Michał Å rajer

将int列表折叠到kotlin中的范围列表

  •  3
  • Michał Å rajer  · 技术社区  · 6 年前

    我有一个整数列表,需要在不丢失任何信息的情况下压缩为整数范围列表(必须有一种方法来反转此操作)。

    目前我有:

    val ints = listOf(8, 9, 45, 48, 49, 60, 61, 61, 62, 63, 3, 4, 5, 4, 5, 6)
    val out = ints
            .map { it..it }
            .fold(mutableListOf(ints[0]..(ints[0] - 1)),
                    { acc, next ->
                        val prev = acc.last()
                        if (prev.last + 1 == next.first) {
                            acc[acc.lastIndex] = prev.first..next.last
                        } else {
                            acc.add(next)
                        }
                        acc
                    }).toList()
    

    正确产生:

    [8..9, 45..45, 48..49, 60..61, 61..63, 3..5, 4..6]
    

    但我的解决方案中有两个方面我不喜欢,

    1. 由于fold的初始值,它不适用于空列表

    2. 这对科特林来说太冗长了。我觉得这可以用更好的方式解决。

    所以,问题是如何修复1和/或2?

    提前感谢!

    2 回复  |  直到 6 年前
        1
  •  2
  •   hotkey    6 年前

    因为你实际上改变了 acc 并在的所有迭代中返回相同的范围列表 fold ,您可能并不真正需要 折叠 ,即, forEach 足够了。

    然后,将每个数字映射到 it..it 这里似乎是多余的。

    考虑到上面的两个注意事项,可以得到以下稍微简化的解决方案版本:

    val result = mutableListOf<IntRange>()
    ints.forEach {
        val lastRange = result.lastOrNull()
        if (lastRange?.endInclusive == it - 1)
            result[result.lastIndex] = lastRange.first..it
        else
            result += it..it
    }
    
        2
  •  1
  •   Todd    6 年前

    我的解决方案看起来没什么不同,但我能够解决您的空列表问题:

    val out = ints.fold(mutableListOf<IntRange>()) { acc, next ->
        acc.apply {
            if(isNotEmpty() && last().endInclusive.inc() == next) {
                this[lastIndex] = this[lastIndex].start .. next
            } else {
                add(next..next)
            }
        }
    }
    

    它的映射也少了一点,使用apply消除了一些冗长的内容,并且必须引用 acc 在最后。