在Scala中调整嵌套循环

时间:2011-08-04 09:19:40

标签: scala

我想知道我是否可以调整以下Scala代码:

def removeDuplicates(listOfTuple: List[(Class1,Class2)]): List[(Class1,Class2)] = {
           var listNoDuplicates: List[(Class1, Class2)] = Nil
           for (outerIndex <- 0 until listOfTuple.size) {
             if (outerIndex != listOfTuple.size - 1)
               for (innerIndex <- outerIndex + 1 until listOfTuple.size) {
                 if (listOfTuple(i)._1.flag.equals(listOfTuple(j)._1.flag))
                   listNoDuplicates = listOfTuple(i) :: listNoDuplicates
               }
           }
           listNoDuplicates
         }

3 个答案:

答案 0 :(得分:5)

通常情况下,如果你看起来像:

var accumulator: A = new A
for( b <- collection ) {
    accumulator = update(accumulator, b)
}
val result = accumulator

可以转换为:

val result = collection.foldLeft( new A ){ (acc,b) => update( acc, b ) }

所以在这里我们可以先使用地图强制标记的单一性。假设该标志的类型为F:

val result = listOfTuples.foldLeft( Map[F,(ClassA,ClassB)] ){
            ( map, tuple ) => map + ( tuple._1.flag -> tuple )
          }

然后可以从地图中提取剩余的元组并转换为列表:

val uniqList = map.values.toList

如果你想保留第一个元组,将foldLeft替换为foldRight反转lambda的参数,它将保持最后一个元组。

示例:

case class ClassA( flag: Int )
case class ClassB( value: Int )

val listOfTuples = 
  List( (ClassA(1),ClassB(2)), (ClassA(3),ClassB(4)), (ClassA(1),ClassB(-1)) )

val result = listOfTuples.foldRight( Map[Int,(ClassA,ClassB)]() ) {
  ( tuple, map ) => map + ( tuple._1.flag -> tuple )
}

val uniqList = result.values.toList

//uniqList: List((ClassA(1),ClassB(2)), (ClassA(3),ClassB(4)))

修改:如果您需要保留初始列表的顺序,请改用:

val uniqList = listOfTuples.filter( result.values.toSet )

答案 1 :(得分:2)

这编译,但由于我无法测试,很难说它是否“正确的事”(tm):

def removeDuplicates(listOfTuple: List[(Class1,Class2)]): List[(Class1,Class2)] = 
  (for {outerIndex <- 0 until listOfTuple.size
     if outerIndex != listOfTuple.size - 1
     innerIndex <- outerIndex + 1 until listOfTuple.size
     if listOfTuple(i)._1.flag == listOfTuple(j)._1.flag
  } yield listOfTuple(i)).reverse.toList

请注意,您可以使用==代替equals(如果您需要引用相等,请使用eq。)

BTW:https://codereview.stackexchange.com/更适合此类问题。

答案 2 :(得分:1)

不要将索引与列表一起使用(例如listOfTuple(i))。列表索引的性能非常糟糕。所以,有些方法......

最简单:

def removeDuplicates(listOfTuple: List[(Class1,Class2)]): List[(Class1,Class2)] =
  SortedSet(listOfTuple: _*)(Ordering by (_._1.flag)).toList

这将保留列表的最后一个元素。如果您希望它保留第一个元素,请改为传递listOfTuple.reverse。由于排序,性能最多只能是O(nlogn)。所以,这是一种更快的方法,使用可变HashSet

def removeDuplicates(listOfTuple: List[(Class1,Class2)]): List[(Class1,Class2)] = {
  // Produce a hash map to find the duplicates
  import scala.collection.mutable.HashSet
  val seen = HashSet[Flag]()

  // now fold
  listOfTuple.foldLeft(Nil: List[(Class1,Class2)]) {
    case (acc, el) =>
      val result = if (seen(el._1.flag)) acc else el :: acc
      seen += el._1.flag
      result
  }.reverse
}

可以通过两种方式避免使用 mutable HashSet

  1. seen设为var,以便可以更新。
  2. 将集合与正在创建的列表一起传递。案件就变成了:

    case ((seen, acc), el) =>