No Scala, como removo duplicatas de uma lista?

94

Suponha que eu tenha

val dirty = List("a", "b", "a", "c")

Existe uma operação de lista que retorna "a", "b", "c"

Deltanovember
fonte

Respostas:

175

Dê uma olhada no ScalaDoc for Seq ,

scala> dirty.distinct
res0: List[java.lang.String] = List(a, b, c)

Atualize . Outros sugeriram usar em Setvez de List. Tudo bem, mas esteja ciente de que, por padrão, a Setinterface não preserva a ordem dos elementos. Você pode querer usar uma implementação de Set que preserva explicitamente a ordem, como collection.mutable.LinkedHashSet .

Kipton Barros
fonte
2
E se você tiver uma lista de arquivos e precisar comparar algo como parte do nome do arquivo?
ozônio
4
@ozone Pergunta interessante. Talvez a maneira mais fácil seja criar um novo mapa de tipo Map[String, File], onde as chaves são a parte do nome do arquivo de interesse. Assim que o mapa for construído, você pode chamar o valuesmétodo para obter um Iterabledos valores - as chaves serão todas distintas por construção.
Kipton Barros
@KiptonBarros e eu acho que você pode fazer isso usando o groupBymembro de scala.collection.Iterable[A].
Louis-Jacob Lebel
18

scala.collection.immutable.Listagora tem um .distinctmétodo.

Portanto, dirty.distinctagora é possível fazer chamadas sem converter para um Setou Seq.

crockpotveggies
fonte
1
.distinctnão está definido para scala.collection.Iterable[A]. Então, nesse caso, você teria que usar upgrade dirtypara a Seqou a de Setqualquer maneira (ou seja, usando um .toList, .toSeqou .toSetmembros) para que isso funcione.
Louis-Jacob Lebel
15

Antes de usar a solução do Kitpon, pense em usar um Setao invés de um List, isso garante que cada elemento seja único.

Como a maioria das operações de lista ( foreach, map, filter, ...) são os mesmos para os conjuntos e listas, mudando coleção poderia ser muito fácil no código.

paradigmático
fonte
7

Usar Set em primeiro lugar é a maneira certa de fazer isso, é claro, mas:

scala> List("a", "b", "a", "c").toSet.toList
res1: List[java.lang.String] = List(a, b, c)

Trabalho. Ou apenas toSetporque suporta oSeq Traversable interface.

zentrope
fonte
1
Editei sua resposta porque Setimplementa Traversable, não Seq. A diferença é que Seqgarante uma ordem aos elementos, enquanto Traversablenão.
Kipton Barros
-3

inArr.distinct foreach println _

Sumit Pal
fonte
isso imprime a saída desejada, o OP não estava pedindo para devolvê-la (como uma lista, presumivelmente)?
RobP
-4

A maneira algorítmica ...

def dedupe(str: String): String = {
  val words = { str split " " }.toList

  val unique = words.foldLeft[List[String]] (Nil) {
    (l, s) => {
      val test = l find { _.toLowerCase == s.toLowerCase } 
      if (test == None) s :: l else l
    }
  }.reverse

  unique mkString " "
}
Farquad
fonte
1
Ele tem uma lista, não uma string. Isso não responde à pergunta.
Tim Gautier