【问题标题】:Check for duplicated values in sortedMap检查 sortedMap 中的重复值
【发布时间】:2021-12-16 04:56:37
【问题描述】:

我有一个初始化为的地图

val cache: SortedMap<String, String> = sortedMapOf()

地图用作缓存,可以包含具有自己唯一键的重复值。我想检查并计算缓存中有多少重复值。请注意,缓存可以包含数百万个条目。

到目前为止,我以这种方式检查重复项

val uniqueValueSet = hashSetOf<String>()
val numDuplicates = cache.filter {!uniqueValueSet.add(it.value)}.count()

但是,我觉得这种检查内存效率低下,将所有不同的值添加到一个集合中会创建一个过时的集合,其中可能包含数百万个元素。

有没有更好、更优化的方法来检查地图中值之间的重复项?

【问题讨论】:

  • 我认为没有 Set 或等效的 Set 没有任何合乎逻辑的方法可以做到这一点,除非您对每个项目进行迭代检查,导致 O(n^2 ) 。您至少可以像这样在更简单的单行中执行此操作,但它当然仍然使用一组:val numDuplicates = cache.size - cache.values.toSet().size 至少它不会创建所有具有重复值的条目的额外列表。
  • 只是想评论一下你计算它们的方式,还有@Tenfour04 的方式非常聪明:)
  • 请注意,您的uniqueValueSet 包含对您的值的引用 - 它不会复制值本身。所以它可能不像你担心的那样需要内存。 (特别是如果您通过调用适当的 HashSet() 构造函数来预先调整它的大小。)

标签: dictionary kotlin duplicates


【解决方案1】:

如果您只对重复的数量感兴趣,您可以这样做:

val numOfDuplicates = cache.size - cache.values.toHashSet().size

它仍然会创建一个包含所有不同值的集合,但这将是唯一的开销。

另一种选择是交换空间复杂度 (O(N) -> O(M),其中 N - cache 的大小,M - 唯一重复的数量;如果 M O(N^2)):

var numOfDuplicates = 0
val duplicates = hashSetOf<String>()
for (value in cache.values) {
    if (value in duplicates) {
        numOfDuplicates++
    } else if (cache.values.atLeastTwo { it == value }) {
        duplicates.add(value)
    }
}

public inline fun <T> Iterable<T>.atLeastTwo(predicate: (T) -> Boolean): Boolean {
    var atLeastOne = false
    for (it in this) {
        if (predicate(it)) {
            if (!atLeastOne) {
                atLeastOne = true
            } else {
                return true
            }
        }
    }
    return false
}

【讨论】:

    【解决方案2】:

    这应该是最快的(灵感来自 Михаил Нафталь 的解决方案):

    val numDuplicates = cache.size - cache.values.distinct().size
    

    编辑 1:我做了一些测试和多达 50.000 个条目(键和值每个 10 个字母数字字符的随机字符串),这确实更快。超过大约 50.000 个条目 Михаил Нафталь 的解决方案变得更快:

    val numOfDuplicates = cache.size - cache.values.toHashSet().size
    

    编辑 2:添加了一些简单的测试:

    val count_of_entries = 1_000_000
    val lengthOfRandomKey = 10
    val lengthOfRandomValue = 10
    
    fun randomString(length: Int): String {
      val charPool: List<Char> = ('a'..'z') + ('A'..'Z') + ('0'..'9')
      return (1..length).map { _ -> kotlin.random.Random.nextInt(0, charPool.size) }.map(charPool::get)
        .joinToString("")
    }
    
    val cache: java.util.SortedMap<String, String> = sortedMapOf()
    repeat (count_of_entries) { cache[randomString(lengthOfRandomKey)] = randomString(lengthOfRandomValue) }
    
    val uniqueValueSet = hashSetOf<String>()
    val start1 = System.nanoTime()
    val numDuplicates1 = cache.filter { !uniqueValueSet.add(it.value) }.count()
    val end1 = System.nanoTime()
    println("$numDuplicates1 duplicates, time ${(end1 - start1).toDouble() / 1_000_000_000} s")
    
    val start2 = System.nanoTime()
    val numDuplicates2 = cache.size - cache.values.toHashSet().size
    val end2 = System.nanoTime()
    println("$numDuplicates2 duplicates, time ${(end2 - start2).toDouble() / 1_000_000_000} s")
    
    val start3 = System.nanoTime()
    val numDuplicates3 = cache.size - cache.values.distinct().size
    val end3 = System.nanoTime()
    println("$numDuplicates3 duplicates, time ${(end3 - start3).toDouble() / 1_000_000_000} s")
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-04-10
      • 1970-01-01
      • 2011-04-14
      • 2012-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多