【问题标题】:Find out frequency of certain integers appearing in an array in Scala找出某些整数出现在Scala数组中的频率
【发布时间】:2021-10-30 01:26:21
【问题描述】:

假设我有两个数组。一组整数的一个数组 A - 全部不同。整数列表的另一个数组 B,都出现在数组 A 中,但不一定不同。例如:

A 可以是 Array(123, 456, 789) B 可以是 Array(123, 123, 456, 123, 789, 456)

我想创建一个数组 C,它告诉我们每个元素(来自数组 A)出现在数组 B 中的频率。在这种情况下,C 将是 Array(3,2,1),因为 123 出现了 3 次, 456出现2次,789出现1次。

在 Scala 中执行此操作的有效方法是什么?

我的尝试是

val C: Array[Int] = Array.fill(3)(0)
var idx = 0

for(i <- A){for(j <- B){if(j == i){C(idx) += 1}}
idx += 1}

for(i <- C){println(i)}

但我知道这可能效率低下,并且如果我要处理更大的数组 A 和数组 B 会花费很长时间。但我仅限于 for 循环和 if 语句,因为我只是 Scala 的初学者.有没有更有效的方法来做到这一点?

【问题讨论】:

  • 为什么你认为这是低效的?问题在于定义O(n),您的解决方案实际上是最有效的方法(好吧,您可以将foreach 替换为while - 但是,您的解决方案不是惯用的,有更多装饰性的方法来解决问题,尽管它们不会那么有效。
  • 其实解决方案有O(A.length * B.length)复杂度
  • This 将是解决问题的惯用方式,没有可变性,不使用普通的Arrays,而是使用像ListÀrraySeq 这样的真实集合,并尝试声明性.此外,我不会返回另一个包含计数的ArraySeq,但我只会返回Map[A, Int] 本身。 -- 再想一想,我相信这个解决方案比你的更快,因为它避免了嵌套循环。

标签: arrays scala


【解决方案1】:

假设n 是数组A 的长度,m 是数组B 的长度。

到目前为止,您的解决方案是O(n * m)

您可以使用mutable HashMapO(n) 额外的空格将其改进为O(n + m)

import scala.collection.mutable

val a = Array(123, 456, 789)
val b = Array(123, 123, 456, 123, 789, 456)

val countMap = mutable.HashMap.empty[Int, Int]

// add all integers in `a` with count 0
for (i <- a) {
  countMap.put(i, 0)
}

// iterate on b
// and update the count in countMap (if exists)
for (i <- b) {
  countMap.get(i).foreach(c => countMap.put(i, c + 1))
}

// fill your array `c`
val c = Array.ofDim[Int](a.length)

for ((i, index) <- a.zipWithIndex) {
  c(index) = countMap.getOrElse(i, 0)
}

println(c.mkString(", "))
// 3, 2, 1
 

请记住,Scala 集合的for's 有其自身的成本,您可以使用 while 循环进一步改进它。

import scala.collection.mutable

val a = Array(123, 456, 789)
val b = Array(123, 123, 456, 123, 789, 456)

val countMap = mutable.HashMap.empty[Int, Int]

// to use with our while loops
var i = 0

// add all integers in `a` with count 0
i = 0
while (i < a.length) {
  countMap.put(a(i), 0)
  i = i + 1
}

// iterate on b
// and update the count in countMap (if exists)
i = 0
while (i < b.length) {
  if (countMap.contains(b(i))) {
    countMap.put(b(i), countMap(b(i)) + 1)
  }
  i = i + 1
}

// fill your array `c`
val c = Array.ofDim[Int](a.length)

i = 0
while (i < a.length) {
  c(i) = countMap.getOrElse(a(i), 0)
  i = i + 1
}

println(c.mkString(", "))
// 3, 2, 1

【讨论】:

  • 既然我们要为原始性能走完整的命令路线,我想知道是否有比HashMap 更好的选择来避免拳击,我可以看到IntMap 但评论说它是被HasMap 取代 - 不管怎样,groupMapReduce 应该很快。
猜你喜欢
  • 2017-07-18
  • 2012-02-12
  • 2011-09-09
  • 1970-01-01
  • 2019-08-31
  • 1970-01-01
  • 2018-04-04
  • 1970-01-01
  • 2023-04-04
相关资源
最近更新 更多