স্কালায় আমি কীভাবে একটি তালিকা থেকে নকল মুছে ফেলব?


96

ধরুন আমার আছে

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

"ক", "খ", "সি" ফেরত দেওয়ার জন্য একটি তালিকা অপারেশন রয়েছে?

উত্তর:


177

জন্য ScalaDoc কটাক্ষপাত আছে seq ,

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

আপডেট । অন্যরা Setবরং ব্যবহার করার পরামর্শ দিয়েছেন List। এটি দুর্দান্ত, তবে জেনে রাখুন যে ডিফল্টরূপে, Setইন্টারফেসটি উপাদান ক্রম সংরক্ষণ করে না। আপনি সেট সেটটি ব্যবহার করতে চাইতে পারেন যা স্পষ্টভাবে অর্ডার সংরক্ষণ করে , যেমন সংগ্রহ.মুট্যাবল.লিংকডহ্যাশসেট


4
আপনার যদি ফাইলগুলির একটি তালিকা থাকে এবং ফাইল নামের অংশের মতো কোনও কিছুর সাথে তুলনা করতে চান তবে কী হবে?
ওজোন

4
@ জোন আকর্ষণীয় প্রশ্ন। সম্ভবত সবচেয়ে সহজ উপায় হ'ল প্রকারের একটি নতুন মানচিত্র তৈরি করা Map[String, File], যেখানে কীগুলি আগ্রহের ফাইল নামের অংশ। মানচিত্রটি তৈরি হয়ে গেলে, আপনি মানগুলির valuesএকটি পেতে পদ্ধতিটি কল করতে পারেন Iterable- কীগুলি সমস্ত নির্মাণ দ্বারা আলাদা হবে be
কিপটন ব্যারোস

@ কিপটনবারস এবং আমি মনে করি আপনি এর groupByসদস্য ব্যবহার করে এটি করতে পারবেন scala.collection.Iterable[A]
লুই-জ্যাকব লেবেল

19

scala.collection.immutable.Listএখন একটি .distinctপদ্ধতি আছে।

কলিং তাই dirty.distinctএকটি রূপান্তর করা ছাড়াই এখন সম্ভব Setবা Seq


4
.distinctজন্য সংজ্ঞায়িত করা হয় না scala.collection.Iterable[A]। সুতরাং যে ক্ষেত্রে, আপনি আপগ্রেড ব্যবহার করতে হবে চাই dirtyএকটি থেকে Seqবা Setকোন পথে (হয় ব্যবহার করে অর্থাত .toList, .toSeqবা .toSetএটির জন্য কাজ করতে সদস্য)।
লুই-জ্যাকব লেবেল

15

Kitpon এর সমাধান ব্যবহারের আগে, একটি ব্যবহার সম্পর্কে মনে Setএকটি বদলে List, এটা নিশ্চিত করে প্রতিটি উপাদান অনন্য।

সবচেয়ে তালিকা অপারেশন হিসাবে ( foreach, map, filter, ...) সেট এবং তালিকার জন্য একই পরিবর্তন সংগ্রহে খুব সহজ কোডে হতে পারে।


7

প্রথমে সেট ব্যবহার করা এটি করার সঠিক উপায় অবশ্যই, তবে:

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

কাজ। বা ঠিক toSetযেমন এটি সমর্থন করেসিক Traversable ইন্টারফেস.


4
আমি আপনার উত্তর সম্পাদনা করেছি কারণ Setপ্রয়োগ Traversable, না Seq। পার্থক্যটি হ'ল Seqউপাদানগুলিকে একটি আদেশের গ্যারান্টি দেয়, যেখানে Traversableহয় না।
কিপটন ব্যারো

0

ইতিমধ্যে সাজানো তালিকার জন্য

আপনি যদি জানেন এমন কোনও তালিকার স্বতন্ত্র আইটেমগুলি চান যা আপনি জানেন যে ইতিমধ্যে সাজানো হয়েছে , যেমন আমার প্রায়শই প্রয়োজন হয়, নীচেরগুলি গতির দ্বিগুণ হিসাবে সম্পাদন করে .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")
  }
}

এটি কেবলমাত্র 100 টি অনন্য মূল্য রয়েছে বলে এটি বেশ দক্ষ, তবে আপনি যখন অপরিবর্তনীয় কাঠামোটি ব্যবহার করছেন তখন আরও অনেকগুলি উপস্থিত থাকলে আপনি সমস্যার মধ্যে পড়তে পারেন। আরও দ্রুত যেতে, আপনি একটি পরিবর্তনীয় কাঠামো সহ এটি বাস্তবায়ন করতে পারেন।
নিক

@ নিক আমি প্রাথমিকভাবে ভেবেছিলাম এটিও সেভাবেই হবে তবে উপরের সম্পাদনাগুলি দেখুন।
ভক্সয়েড

আমি উপরোক্ত বিষয়গুলি নিজেই চেষ্টা করে দেখেছি কেন অপরিবর্তনীয় এর জন্য আরও ভাল হবে তা আমি বুঝতে পারি না তবে আপনি যদি স্বতন্ত্র মূল্যবোধের সংখ্যা উল্লেখযোগ্যভাবে বৃদ্ধি করেন তাও এটি এমনভাবেই চলতে থাকে। আমি কয়েকটি পরিবর্তনীয় কাঠামো চেষ্টা করেছিলাম যেখানে প্রিপেন্ড বেশি দক্ষ তবে এমনকি ফলাফলটি ধীরে ধীরে ধীরে ধীরে না ঘটিয়েও।
নিক

0

আপনি পুনরাবৃত্তি এবং প্যাটার্ন মিলও ব্যবহার করতে পারেন:

def removeDuplicates[T](xs: List[T]): List[T] = xs match {
  case Nil => xs
  case head :: tail => head :: removeDuplicates(for (x <- tail if x != head) yield x)
}


4
removeDuplicates(tail.filter(_ != head))
jwvh

-3

inArr.distinct foreach মুদ্রণ _


এটি পছন্দসই আউটপুট প্রিন্ট করে, ওপি কি এটি ফেরত দিতে বলছিল না (সম্ভবত একটি তালিকা হিসাবে)?
রবপি

-5

অ্যালগরিদমিক উপায় ...

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 " "
}

4
তার একটি তালিকা আছে, স্ট্রিং নয়। এটি প্রশ্নের উত্তর দেয় না।
টিম গৌটিয়ার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.