kotlin循环遍历2个不同长度的列表

时间:2020-10-27 15:36:57

标签: kotlin

希望您能给我一些有关我已解决但不满意的问题的建议。

我有这个代码

val allTeams = (0 until teamNumber)
        .map { Team() }

var idx = 0
playerNames.filter { it.isNotBlank() }
     .map {
         it.trim()
         it.capitalize(Locale.ROOT)
     }
     .shuffled()
     .forEach {
         allTeams[idx].addPlayer(it)
         if(idx == allTeams.size - 1) idx = 0 else idx++
     }

例如,如果我给此代码teamNumber 3和玩家名称['a','b','c','d','e'],例如,它将创建3个团队,然后循环遍历玩家名称并将其放入在团队中,如果达到allTeams的最大长度,它将var idx更改为0并继续运行。

我的问题是,有没有办法在不维护该丑陋索引var的情况下做到这一点?

这是我使用递归的另一种解决方案,但也不是很好。

tailrec fun addToTeam(  names: List<String>, teamIdx: Int = 0, nameIdx: Int = 0){
        if (nameIdx == names.size) return
        allTeams[teamIdx].addPlayer(names[nameIdx])
        if (teamIdx == allTeams.size - 1) addToTeam(names,0, nameIdx+1 )
        else addToTeam(names,teamIdx+1, nameIdx+1 )
    }

谢谢!

2 个答案:

答案 0 :(得分:2)

一个有趣的问题!

是的,您的代码有点丑陋,但我找不到更整洁的解决方案。

首先,进行一些小调整:idx这个名字是毫无意义的,可能会造成混淆;也许像teamIdx这样的东西会更清楚。相反,allTeams可能只是teams。并且更常见的更新方式是:

teamIdx = (teamIdx + 1) % teams.size

但是,这没有太大帮助。

一种方法可能是将名称分成多个块,然后与团队一起压缩每个块:

playerNames
    // filter &c here
    .chunked(teams.size)
    .forEach {
        it.zip(teams).forEach { (player, team) ->
            team += player
        }
    }

这也很丑陋,因为它没有嵌套嵌套的forEach()调用(只有一个),而有两个(emem)嵌套(两个)。但这避免了显式索引。

就像您的代码一样,如果玩家数量不是团队数量的确切倍数,则此方法可以正确应对。如果您一直知道,那么使用addAll()而不是第二个forEach()可能会有更好的方法。

如果我正在写这篇文章,我可能会拆分出一个实用函数以使其更加清晰。也许功能类似于zip(),但重复第二个列表直到第一个列表的末尾。或将列表均匀地分成几乎相等大小的组的函数,例如chunked(),但让块大小改变1,而不是让最后一个块小得多。

答案 1 :(得分:1)

我想提出另一种方法,将团队的创建与向其添加玩家相结合:

val players = playerNames.filter { it.isNotBlank() }
    .map { it.trim().capitalize(Locale.ROOT) }
    .shuffled()

val allTeams = if (players.size < teamNumber) {
    List(teamNumber) { index ->
        Team().also { if (index < players.size) it.addPlayer(players[index]) }
    }
} else {
    val lastChunkSize = players.size % teamNumber
    val lastChunk = players.takeLast(lastChunkSize)
    players
        .dropLast(lastChunkSize)
        .chunked(playerNames.size / teamNumber)
        .mapIndexed { index, chunk ->
            Team(chunk).also { if (index < lastChunkSize) it.addPlayer(lastChunk[index]) }
        }
}

请注意,该代码假定Team类中有一个接受玩家列表的构造函数。