मान लो मेरे पास है
val dirty = List("a", "b", "a", "c")
क्या एक सूची ऑपरेशन है जो "ए", "बी", "सी" लौटाता है
मान लो मेरे पास है
val dirty = List("a", "b", "a", "c")
क्या एक सूची ऑपरेशन है जो "ए", "बी", "सी" लौटाता है
जवाबों:
Seq के लिए ScalaDoc पर एक नजर है ,
scala> dirty.distinct
res0: List[java.lang.String] = List(a, b, c)
अपडेट करें । दूसरों ने Set
इसके बजाय उपयोग करने का सुझाव दिया है List
। यह ठीक है, लेकिन ध्यान रखें कि डिफ़ॉल्ट रूप से, Set
इंटरफ़ेस तत्व आदेश को संरक्षित नहीं करता है। आप एक सेट कार्यान्वयन का उपयोग करना चाह सकते हैं जो स्पष्ट रूप से आदेश को संरक्षित करता है, जैसे संग्रह .utable.inkedHashSet ।
Map[String, File]
, जहां चाबियाँ ब्याज की फ़ाइल नाम का हिस्सा हैं। एक बार जब मानचित्र का निर्माण हो जाता है, तो आप मूल्यों values
को प्राप्त करने के लिए विधि को कॉल कर सकते Iterable
हैं - कुंजी सभी निर्माण से अलग होगी।
groupBy
सदस्य का उपयोग करके ऐसा कर सकते हैं scala.collection.Iterable[A]
।
scala.collection.immutable.List
अब एक .distinct
विधि है।
इसलिए, या में dirty.distinct
कनवर्ट किए बिना कॉल करना अब संभव है ।Set
Seq
.distinct
के लिए परिभाषित नहीं है scala.collection.Iterable[A]
। तो उस स्थिति में, आप उन्नयन का उपयोग करना होगा dirty
एक करने के लिए Seq
या एक Set
वैसे भी (या तो का उपयोग करके यानी .toList
, .toSeq
या .toSet
काम करने के लिए इस के लिए सदस्य)।
किटपॉइंट के समाधान का उपयोग करने से पहले, ए के Set
बजाय उपयोग करने के बारे में सोचें List
, यह सुनिश्चित करता है कि प्रत्येक तत्व अद्वितीय है।
अधिकांश सूची संचालन ( foreach
और map
, filter
...,) सेट और सूचियों के लिए समान हैं, कोड में संग्रह बदलना बहुत आसान हो सकता है।
पहली जगह में सेट का उपयोग करना सही तरीका है, बेशक, लेकिन:
scala> List("a", "b", "a", "c").toSet.toList
res1: List[java.lang.String] = List(a, b, c)
काम करता है। या केवलtoSet
कि यह समर्थन करता हैseq Traversable
इंटरफेस।
Set
लागू Traversable
नहीं, नहीं Seq
। अंतर यह है कि Seq
तत्वों को एक आदेश की गारंटी देता है, जबकि Traversable
नहीं करता है।
यदि आप किसी ऐसी सूची के अलग-अलग आइटम चाहते हैं, जिसे आप जानते हैं कि पहले से ही सॉर्ट किया गया है , जैसा कि मुझे अक्सर ज़रूरत होती है, तो निम्न गति के बारे में दोगुना होता है .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 से 100,000,000 यादृच्छिक किलों की सूची पर प्रदर्शन के परिणाम:
distinct : 0.6655373s
distinctOnSorted: 0.2848134s
हालांकि ऐसा लगता है कि एक अधिक उत्परिवर्ती / गैर-कार्यात्मक प्रोग्रामिंग दृष्टिकोण एक अपरिवर्तनीय सूची से बाहर निकलने की तुलना में तेज हो सकता है, अन्यथा अभ्यास से पता चलता है। अपरिवर्तनीय कार्यान्वयन लगातार बेहतर प्रदर्शन करता है। इस कारण से मेरा अनुमान है कि स्काला अपने संकलक अनुकूलन को अपरिवर्तनीय संग्रह पर केंद्रित करता है, और उस पर एक अच्छा काम करता है। (बेहतर क्रियान्वयन प्रस्तुत करने के लिए मैं दूसरों का स्वागत करता हूं।)
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
कार्यान्वयन:
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
}
}
परीक्षा:
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")
}
}
एल्गोरिथम तरीका ...
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 " "
}