我想知道我是否可以调整以下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
}
答案 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
:
seen
设为var,以便可以更新。将集合与正在创建的列表一起传递。案件就变成了:
case ((seen, acc), el) =>