希望您能给我一些有关我已解决但不满意的问题的建议。
我有这个代码
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 )
}
谢谢!
答案 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
类中有一个接受玩家列表的构造函数。