Varsayalım ki bende
val dirty = List("a", "b", "a", "c")
"A", "b", "c" döndüren bir liste işlemi var mı
Varsayalım ki bende
val dirty = List("a", "b", "a", "c")
"A", "b", "c" döndüren bir liste işlemi var mı
Yanıtlar:
Seq için ScalaDoc'a bir göz atın ,
scala> dirty.distinct
res0: List[java.lang.String] = List(a, b, c)
Güncelle . Diğerleri Set
yerine kullanmayı önerdiler List
. Sorun değil, ancak varsayılan olarak Set
arayüzün öğe sırasını korumadığını unutmayın. Açıkça bir ayarla uygulamasını kullanmak isteyebilirsiniz yok gibi, düzeni korumak collection.mutable.LinkedHashSet .
Map[String, File]
tuşlarını kullanarak ilgili dosya adının parçasıdır. Harita oluşturulduktan sonra, values
bir Iterable
değer elde etmek için yöntemi çağırabilirsiniz - anahtarların tümü yapı itibariyle farklı olacaktır.
groupBy
üyesini kullanarak yapabilirsiniz scala.collection.Iterable[A]
.
scala.collection.immutable.List
artık bir .distinct
yöntemi var.
Yani dirty.distinct
, artık a Set
veya biçimine dönüştürmeden arama yapmak mümkündür Seq
.
.distinct
için tanımlanmamıştır scala.collection.Iterable[A]
. Bu durumda, bunun çalışması dirty
için a Seq
veya Set
a'ya yükseltme kullanmanız gerekir (yani .toList
, .toSeq
veya .toSet
üyelerini kullanarak ).
Kitpon'un çözümünü kullanmadan önce, a Set
yerine a kullanmayı düşünün List
, bu her bir öğenin benzersiz olmasını sağlar.
En liste işlemleri gibi ( foreach
, map
, filter
, ...) setleri ve listeler için aynıdır, koleksiyon değişen çok kolay kodunda olabilir.
İlk etapta Set kullanmak, elbette bunu yapmanın doğru yoludur, ancak:
scala> List("a", "b", "a", "c").toSet.toList
res1: List[java.lang.String] = List(a, b, c)
İşler. Veya toSet
desteklediği gibiSıra Traversable
arayüz.
Set
uygular Traversable
, değil Seq
. Aradaki fark, Seq
unsurlar için bir düzen garanti ederken Traversable
, garanti etmemesidir.
Sıklıkla ihtiyaç duyduğum gibi, bildiğiniz bir listenin farklı öğelerinin halihazırda sıralanmasını istiyorsanız , aşağıdakiler yaklaşık iki kat hız sağlar .distinct
:
def distinctOnSorted[V](seq: List[V]): List[V] =
seq.foldLeft(List[V]())((result, v) =>
if (result.isEmpty || v != result.head) v :: result else result)
.reverse
0-99 arası 100.000.000 rastgele İntlik bir listede performans sonuçları:
distinct : 0.6655373s
distinctOnSorted: 0.2848134s
Daha değişken / işlevsel olmayan bir programlama yaklaşımı, değişmez bir listenin başına geçmekten daha hızlı olabilir gibi görünse de, uygulama aksini gösterir. Değişmez uygulama sürekli olarak daha iyi performans gösterir. Tahminime göre scala derleyici optimizasyonlarını değişmez koleksiyonlara odaklıyor ve bunda iyi bir iş çıkarıyor. (Başkalarının daha iyi uygulamalar sunmasını memnuniyetle karşılıyorum.)
List size 1e7, random 0 to 1e6
------------------------------
distinct : 4562.2277ms
distinctOnSorted : 201.9462ms
distinctOnSortedMut1: 4399.7055ms
distinctOnSortedMut2: 246.099ms
distinctOnSortedMut3: 344.0758ms
distinctOnSortedMut4: 247.0685ms
List size 1e7, random 0 to 100
------------------------------
distinct : 88.9158ms
distinctOnSorted : 41.0373ms
distinctOnSortedMut1: 3283.8945ms
distinctOnSortedMut2: 54.4496ms
distinctOnSortedMut3: 58.6073ms
distinctOnSortedMut4: 51.4153ms
Uygulamalar:
object ListUtil {
def distinctOnSorted[V](seq: List[V]): List[V] =
seq.foldLeft(List[V]())((result, v) =>
if (result.isEmpty || v != result.head) v :: result else result)
.reverse
def distinctOnSortedMut1[V](seq: List[V]): Seq[V] = {
if (seq.isEmpty) Nil
else {
val result = mutable.MutableList[V](seq.head)
seq.zip(seq.tail).foreach { case (prev, next) =>
if (prev != next) result += next
}
result //.toList
}
}
def distinctOnSortedMut2[V](seq: List[V]): Seq[V] = {
val result = mutable.MutableList[V]()
if (seq.isEmpty) return Nil
result += seq.head
var prev = seq.head
for (v <- seq.tail) {
if (v != prev) result += v
prev = v
}
result //.toList
}
def distinctOnSortedMut3[V](seq: List[V]): List[V] = {
val result = mutable.MutableList[V]()
if (seq.isEmpty) return Nil
result += seq.head
var prev = seq.head
for (v <- seq.tail) {
if (v != prev) v +=: result
prev = v
}
result.reverse.toList
}
def distinctOnSortedMut4[V](seq: List[V]): Seq[V] = {
val result = ListBuffer[V]()
if (seq.isEmpty) return Nil
result += seq.head
var prev = seq.head
for (v <- seq.tail) {
if (v != prev) result += v
prev = v
}
result //.toList
}
}
Ölçek:
import scala.util.Random
class ListUtilTest extends UnitSpec {
"distinctOnSorted" should "return only the distinct elements in a sorted list" in {
val bigList = List.fill(1e7.toInt)(Random.nextInt(100)).sorted
val t1 = System.nanoTime()
val expected = bigList.distinct
val t2 = System.nanoTime()
val actual = ListUtil.distinctOnSorted[Int](bigList)
val t3 = System.nanoTime()
val actual2 = ListUtil.distinctOnSortedMut1(bigList)
val t4 = System.nanoTime()
val actual3 = ListUtil.distinctOnSortedMut2(bigList)
val t5 = System.nanoTime()
val actual4 = ListUtil.distinctOnSortedMut3(bigList)
val t6 = System.nanoTime()
val actual5 = ListUtil.distinctOnSortedMut4(bigList)
val t7 = System.nanoTime()
actual should be (expected)
actual2 should be (expected)
actual3 should be (expected)
actual4 should be (expected)
actual5 should be (expected)
val distinctDur = t2 - t1
val ourDur = t3 - t2
ourDur should be < (distinctDur)
print(s"distinct : ${distinctDur / 1e6}ms\n")
print(s"distinctOnSorted : ${ourDur / 1e6}ms\n")
print(s"distinctOnSortedMut1: ${(t4 - t3) / 1e6}ms\n")
print(s"distinctOnSortedMut2: ${(t5 - t4) / 1e6}ms\n")
print(s"distinctOnSortedMut3: ${(t6 - t5) / 1e6}ms\n")
print(s"distinctOnSortedMut4: ${(t7 - t6) / 1e6}ms\n")
}
}
Algoritmik yol ...
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 " "
}