admin管理员组文章数量:1400174
I am declaring a map literal in my code. This eventually will be a long map and has a chance of keys being repeated that I want to avoid. Also, I don't want to sort declaration based on keys to keep them grouped based on what source they were picked from and easy to add to the list.
I am using IntelliJ Idea and I'm ok if I can set some inspection preference to highlight any duplicate keys. I tried looking up but didn't find any. I also tried using detekt plugin to highlight the issue for me, but couldn't get it working either.
Following is a small example of a map with duplicate keys that Kotlin allows, but I want to be highlighted in the editor so that I can avoid it:
val MF_RR_HeaderMap = mapOf<String, MFRRHeader>(
// Source 1
"unit" to MFRRHeader.UNIT_NUMBER,
"unit type" to MFRRHeader.UNIT_TYPE,
"resident code" to MFRRHeader.TENANT_CODE,
"resident name" to MFRRHeader.TENANT_NAME,
// first entry
"market rent" to MFRRHeader.MARKET_RENT,
// Source 2
"type" to MFRRHeader.UNIT_TYPE,
"sq. feet" to MFRRHeader.SQFT,
"residents" to MFRRHeader.TENANT_NAME,
"status" to MFRRHeader.STATUS,
// This is the duplicate entry that I want to be highlighted
"market rent" to MFRRHeader.STATUS,
)
I am declaring a map literal in my code. This eventually will be a long map and has a chance of keys being repeated that I want to avoid. Also, I don't want to sort declaration based on keys to keep them grouped based on what source they were picked from and easy to add to the list.
I am using IntelliJ Idea and I'm ok if I can set some inspection preference to highlight any duplicate keys. I tried looking up but didn't find any. I also tried using detekt plugin to highlight the issue for me, but couldn't get it working either.
Following is a small example of a map with duplicate keys that Kotlin allows, but I want to be highlighted in the editor so that I can avoid it:
val MF_RR_HeaderMap = mapOf<String, MFRRHeader>(
// Source 1
"unit" to MFRRHeader.UNIT_NUMBER,
"unit type" to MFRRHeader.UNIT_TYPE,
"resident code" to MFRRHeader.TENANT_CODE,
"resident name" to MFRRHeader.TENANT_NAME,
// first entry
"market rent" to MFRRHeader.MARKET_RENT,
// Source 2
"type" to MFRRHeader.UNIT_TYPE,
"sq. feet" to MFRRHeader.SQFT,
"residents" to MFRRHeader.TENANT_NAME,
"status" to MFRRHeader.STATUS,
// This is the duplicate entry that I want to be highlighted
"market rent" to MFRRHeader.STATUS,
)
Share
Improve this question
asked Mar 25 at 11:22
chetan vermachetan verma
436 bronze badges
1
- Thanks @kent and @andrewl! I am going with Kent's answer as I can reuse the same function for other maps declarations as well. – chetan verma Commented Mar 25 at 12:03
3 Answers
Reset to default 3You can write a function wrapping the standard mapOf, and throw IAE when duplicate keys hit:
public fun <K, V> myMapOf(vararg pairs: Pair<K, V>): Map<K, V> {
val dupKeys = pairs.groupingBy { it.first }.eachCount().filter { it.value > 1 }
require(dupKeys.isEmpty()) { "duplicate keys: ${dupKeys.keys.joinToString(separator = ", ")}" }
return mapOf(*pairs)
}
val oops = myMapOf(
"a" to "b",
"b" to "c",
"c" to "d",
"a" to "e",
"b" to "f",
)
You can also play it on the playground
Two approaches
- Write yourself some kind of annotation processor that runs at compile time (I cannot help you with that)
- Write it a bit differently and have a unit test to verify:
val MF_RR_HeaderMap = listOf<Pair<String, MFRRHeader>>(
// Source 1
"unit" to MFRRHeader.UNIT_NUMBER,
...
).let {
val map = mutableMapOf<String, MFRRHeader>()
it.forEach { (key, value) ->
require(map.put(key, value) == null) { "Duplication of key $key" }
}
map
}
Then have a Unit test that simply instantiates the class, and if duplicates exist you will get an error listing the duplicate key
My answer minimizes the runtime overhead of checking for duplicates in map literals. This is desirable because the discovery of duplicates happens at most once per source-code change (ideally it should happen at compile time, but that's difficult to implement) whereas the building of the map happens every time the application is run: potentially thousands of times. You don't want to add runtime overhead every single time the application is run, just because you want to perform a check that is relevant only once in the application's development.
public fun <K, V> noDuplicatesMapOf(vararg pairs: Pair<K, V>) = mapOf(*pairs)
.also {
require(it.size == pairs.size) {
val dups = pairs.groupingBy { it.first }.eachCount().filter { it.value > 1 }
"Map literal has duplicate keys ${dups.keys}"
}
}
val ok = noDuplicatesMapOf(
"a" to 0,
"b" to 1
)
val willThrowIllegalArgumentException = noDuplicatesMapOf(
"a" to 0,
"b" to 1,
"a" to 2,
"b" to 3
)
The check it.size == pairs.size
is so fast that the runtime overhead will be unnoticeable compared to just using mapOf
.
本文标签: Avoid having duplicate keys in a map literal in KotlinStack Overflow
版权声明:本文标题:Avoid having duplicate keys in a map literal in Kotlin - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744200571a2594943.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论