【问题标题】:How to get distinct values from an element within list of tuples in Scala如何从Scala中的元组列表中的元素获取不同的值
【发布时间】:2020-09-11 08:34:30
【问题描述】:

你好,我有这个练习,我试图找到元组的第二个元素中不存在的所有数字,并将它们打印在一个列表中。我有一个工作版本,但它返回重复值,并且没有在列表中返回。我似乎不能在这里使用 distinct 。谁能向我解释为什么这里不能使用 distinct 以及我需要做什么。此外,如果有更好的方法来获得练习的答案,我们将不胜感激。

 object Example{

   def main(args: Array[String]): Unit = {
       val tupleExercise: List[(Int,Int)] = List(
         (1, 3),
         (2, 3),
         (3, 6),
         (5, 6),
         (5, 7),
         (4, 5),
         (4, 8),
         (4, 9),
         (9, 11)
       )

     def notExistsInSecond(n: List[(Int, Int)]): Unit = {
       var potential =
         for (a <- n) {
           for (c <- n) 
             if(c._1 == a._2) println(a._1)
         }
     }
     println(notExistsInSecond(tupleExercise))
   }
 }
//expected ouput
// [1, 2, 4]

【问题讨论】:

  • 您能添加预期的输出吗?您要返回第二个元组值中不存在的元组,还是只返回第一个元组值的值?
  • 你不能使用.distinct,因为没有什么可以使用的。您正在打印结果而不是保存它们。最后一行,println(notExists... 只打印一个空的\n,因为notExistsInSecond() 返回Unit。如果您将结果保存在List 中,那么您可以申请.distinct
  • @RayanRal 我已经更新了预期的输出
  • @jwvh 我不确定如何将结果保存到列表中,你能展示一下实现吗?

标签: scala loops tuples scala-collections


【解决方案1】:

我不认为有一种(高效的)方法可以将它写在一行中,但你可以这样写:

def notExistsInSecond(n: List[(Int, Int)]): List[Int] = {
  val second = n.map(_._2).distinct
  n.map(_._1).distinct.filterNot(second.contains)
}

如果您使用HashSet 而不是List 进行查找,它的性能可能会更高:

def notExistsInSecond(n: List[(Int, Int)]): List[Int] = {
  val valuesSet = n.map(_._2).toSet
  n.map(_._1).distinct.filterNot(valuesSet.contains)
}

【讨论】:

    【解决方案2】:

    这是一种通过单次遍历输入列表并使用Set 来确保不同结果的方法。

    def notExistsInSecond(n: List[(Int, Int)]): List[Int] = {
      val (s1,s2) = n.foldLeft((Set.empty[Int],Set.empty[Int])){
        case ((sa,sb),(a,b)) => (sa+a, sb+b)
      }
      (s1 diff s2).toList
    }
    

    【讨论】:

      【解决方案3】:

      与 Raphael 的逻辑相同,但性能更高。

      def notExistsInSecond[A](n: List[(A, A)]): List[A] = {
        val seconds = n.iterator.map(_._2).toSet
      
        val (result, _) = n.foldLeft(List.empty[Int] -> Set.empty[Int]) {
          case ((result, added), (e, _)) =>
            if (!seconds(e) && !added(e))
              (e :: result) -> (added + e)
            else
              result -> added
        }
      
        result.reverse // If you do not care about the order you can remove this reverse
      }
      

      或者如果你不关心结果是一个列表,这会更快:

      def notExistsInSecond[A](n: List[(A, A)]): Set[A] = {
        val seconds = n.iterator.map(_._2).toSet
      
        n.iterator.collect {
          case (e, _) if (!seconds(e)) => e
        }.toSet
      }
      

      【讨论】:

      • 如果您将其转换为Set,在n 上调用iterator 是否有任何好处?
      • @RaphaelRoth 迭代器使所有后续转换变得惰性。因此map 和到集合的转换是在一次迭代中一起完成的,而不是两次。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-29
      相关资源
      最近更新 更多