আমি কীভাবে স্কালা সংগ্রহগুলিতে সমৃদ্ধ-আমার-গ্রন্থাগার প্যাটার্নটি প্রয়োগ করব?


92

সবচেয়ে শক্তিশালী Scala পাওয়া নিদর্শনগুলোর এক সমৃদ্ধ-মাই-গ্রন্থাগার * প্যাটার্ন, যা অন্তর্নিহিত ধর্মান্তর ব্যবহার হয় প্রদর্শিত গতিশীল পদ্ধতি রেজল্যুশন প্রয়োজন ছাড়া বিদ্যমান ক্লাস পদ্ধতি যোগ করতে। উদাহরণস্বরূপ, আমরা যদি চাইতাম যে সমস্ত স্ট্রিংয়ে এমন পদ্ধতি ছিল যা spacesতাদের কাছে কতগুলি শ্বেতক্ষেত্রের অক্ষর রয়েছে তা গণনা করে আমরা করতে পারি:

class SpaceCounter(s: String) {
  def spaces = s.count(_.isWhitespace)
}
implicit def string_counts_spaces(s: String) = new SpaceCounter(s)

scala> "How many spaces do I have?".spaces
res1: Int = 5

দুর্ভাগ্যক্রমে, জেনেরিক সংগ্রহগুলি নিয়ে কাজ করার সময় এই প্যাটার্নটি সমস্যায় পড়ে। উদাহরণস্বরূপ, সংগ্রহের সাথে ধারাবাহিকভাবে আইটেমগুলি গোষ্ঠীকরণ সম্পর্কে বেশ কয়েকটি প্রশ্ন জিজ্ঞাসা করা হয়েছে । একটি শটে কাজ করে এমন কিছুই নির্মিত হয়নি, সুতরাং এটি জেনেরিক সংগ্রহ ব্যবহার করে সমৃদ্ধ-আমার-লাইব্রেরি প্যাটার্নের জন্য আদর্শ প্রার্থী বলে মনে হচ্ছেC এবং জেনেরিক উপাদান ধরণেরA :

class SequentiallyGroupingCollection[A, C[A] <: Seq[A]](ca: C[A]) {
  def groupIdentical: C[C[A]] = {
    if (ca.isEmpty) C.empty[C[A]]
    else {
      val first = ca.head
      val (same,rest) = ca.span(_ == first)
      same +: (new SequentiallyGroupingCollection(rest)).groupIdentical
    }
  }
}

অবশ্যই, এটি কাজ করে না । আরইপিএল আমাদের বলে:

<console>:12: error: not found: value C
               if (ca.isEmpty) C.empty[C[A]]
                               ^
<console>:16: error: type mismatch;
 found   : Seq[Seq[A]]
 required: C[C[A]]
                 same +: (new SequentiallyGroupingCollection(rest)).groupIdentical
                      ^

দুটি সমস্যা রয়েছে: C[C[A]]খালি C[A]তালিকা (বা পাতলা বাতাস থেকে) কীভাবে আমরা পাই ? এবং কিভাবে আমরা একটি পরিবর্তে লাইন C[C[A]]থেকে ফিরে পেতে ?same +:Seq[Seq[A]]

* পূর্বে পিম্প-মাই-লাইব্রেরি নামে পরিচিত।


4
দুর্দান্ত প্রশ্ন! এবং, আরও ভাল, এটি একটি উত্তর সঙ্গে আসে! :-)
ড্যানিয়েল সি সোব্রাল

4
@ ড্যানিয়েল - দুই বা ততোধিক উত্তর আসার সাথে আমার কোনও আপত্তি নেই!
রেক্স কের

4
ভুলে যাও, বন্ধু। যখনই আমাকে এর মতো কিছু করার দরকার হয় আমি এটি সন্ধান করতে এটি বুকমার্ক করছি। :-)
ড্যানিয়েল সি সোব্রাল

উত্তর:


74

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

সমৃদ্ধ করার ক্ষেত্রে আমাদের সমস্যাটি একই ধরণের সংগ্রহগুলি ফিরে আসার চেষ্টা করার সময় সংগ্রহ লাইব্রেরি নিজেই মুখোমুখি হয়। এটি হ'ল, আমরা সংগ্রহগুলি তৈরি করতে চাই, তবে উদারভাবে কাজ করার সময়, "সংগ্রহটি ইতিমধ্যে একই ধরণের" উল্লেখ করার উপায় আমাদের নেই। সুতরাং আমাদের নির্মাতাদের দরকার ।

এখন প্রশ্ন: আমরা আমাদের বিল্ডারগুলি কোথা থেকে পাব? সুস্পষ্ট জায়গাটি সংগ্রহ থেকেই। এটি কাজ করে না । আমরা ইতিমধ্যে সিদ্ধান্ত নিয়েছি, জেনেরিক সংগ্রহের দিকে যাওয়ার আগে আমরা সংগ্রহের ধরণটি ভুলে যাব। সুতরাং যদিও সংগ্রহটি এমন কোনও বিল্ডারকে ফিরিয়ে দিতে পারে যা আমরা যে ধরণের পছন্দ করতে পারি তার আরও সংগ্রহ উত্পন্ন করে, তবে প্রকারটি কী তা তা জানত না।

পরিবর্তে, আমরা CanBuildFromচারপাশে ভাসমান প্রভাব থেকে আমাদের বিল্ডারদের পেতে । এগুলি ইনপুট এবং আউটপুট ধরণের সাথে মেলে এবং আপনাকে উপযুক্ত টাইপ করা বিল্ডার দেওয়ার উদ্দেশ্যে বিশেষভাবে বিদ্যমান।

সুতরাং, আমাদের তৈরির জন্য দুটি ধারণামূলক লাফিয়ে উঠেছে:

  1. আমরা মান সংগ্রহের ক্রিয়াকলাপ ব্যবহার করছি না, আমরা বিল্ডার ব্যবহার করছি।
  2. আমরা এই বিল্ডারগুলি CanBuildFromসরাসরি আমাদের সংগ্রহ থেকে নয়, অন্তর্নিহিত এস থেকে পাই get

আসুন একটি উদাহরণ তাকান।

class GroupingCollection[A, C[A] <: Iterable[A]](ca: C[A]) {
  import collection.generic.CanBuildFrom
  def groupedWhile(p: (A,A) => Boolean)(
    implicit cbfcc: CanBuildFrom[C[A],C[A],C[C[A]]], cbfc: CanBuildFrom[C[A],A,C[A]]
  ): C[C[A]] = {
    val it = ca.iterator
    val cca = cbfcc()
    if (!it.hasNext) cca.result
    else {
      val as = cbfc()
      var olda = it.next
      as += olda
      while (it.hasNext) {
        val a = it.next
        if (p(olda,a)) as += a
        else { cca += as.result; as.clear; as += a }
        olda = a
      }
      cca += as.result
    }
    cca.result
  }
}
implicit def iterable_has_grouping[A, C[A] <: Iterable[A]](ca: C[A]) = {
  new GroupingCollection[A,C](ca)
}

চলুন, এটি আলাদা করা যাক। প্রথমত, সংগ্রহের সংগ্রহগুলি তৈরি করতে, আমরা জানি যে আমাদের দুটি ধরণের সংগ্রহ তৈরি করতে হবে: C[A]প্রতিটি দলের জন্য এবং C[C[A]]যা সমস্ত দলকে একত্রিত করে। সুতরাং, আমাদের দু'জন নির্মাতা দরকার, একজন যা গ্রহণ Aকরে এবং সেগুলি তৈরি করে C[A], এবং যেগুলি গ্রহণ C[A]করে এবং C[C[A]]এস তৈরি করে । এর স্বাক্ষর প্রকারের দিকে তাকিয়ে CanBuildFromআমরা দেখতে পাই

CanBuildFrom[-From, -Elem, +To]

যার অর্থ ক্যানবিল্ডফর্ম আমরা যে ধরণের সংগ্রহের সাথে শুরু করছি তা জানতে চায় - আমাদের ক্ষেত্রে এটি C[A]এবং তারপরে উত্পন্ন সংগ্রহের উপাদানগুলি এবং সেই সংগ্রহের ধরণটি । সুতরাং আমরা সেগুলি পূরণ করি নিখুঁত পরামিতি হিসাবে cbfccএবং cbfc

এটি বুঝতে পেরে, এটি বেশিরভাগ কাজ। CanBuildFromআমাদের বিল্ডারদের দেওয়ার জন্য আমরা আমাদের গুলি ব্যবহার করতে পারি (আপনাকে যা করতে হবে সেগুলি প্রয়োগ করতে হবে)। এবং একজন নির্মাতা +=এটির সাথে একটি সংগ্রহ তৈরি করতে পারে , এটি সংগ্রহের সাথে রূপান্তর করতে পারে যা শেষ পর্যন্ত তার সাথে থাকার কথা result, এবং নিজেই খালি হয় এবং আবার শুরু করার জন্য প্রস্তুত থাকে clear। নির্মাতারা খালি শুরু করে, যা আমাদের প্রথম সংকলন ত্রুটি সমাধান করে এবং আমরা যেহেতু পুনর্বার পরিবর্তে বিল্ডার ব্যবহার করছি, দ্বিতীয় ত্রুটিটিও চলে যায়।

একটি শেষ সামান্য বিশদ - আসলে কাজটি করে এমন অ্যালগরিদম ব্যতীত - অন্তর্নিহিত রূপান্তর। নোট করুন যে আমরা ব্যবহার করি new GroupingCollection[A,C]না [A,C[A]]। এটি কারণ শ্রেণি ঘোষণাটি Cএকটি প্যারামিটারের সাথে ছিল , যা এটি এতে Aপাসের সাথে এটি পূরণ করে। সুতরাং আমরা কেবল এটি টাইপ Cকরি এবং এটি এটি তৈরি C[A]করতে দিন । গৌণ বিশদ, তবে আপনি অন্য কোনও উপায়ে চেষ্টা করলে সংকলন-সময় ত্রুটিগুলি পাবেন।

এখানে, আমি "সমতুল্য উপাদানগুলি" সংগ্রহের তুলনায় পদ্ধতিটিকে কিছুটা জেনেরিক করে তুলেছি - বরং, যখনই এর ক্রমিক উপাদানগুলির পরীক্ষা ব্যর্থ হয় তখন পদ্ধতিটি মূল সংগ্রহটি আলাদা করে দেয়।

চলুন আমাদের কার্য পদ্ধতিটি দেখুন:

scala> List(1,2,2,2,3,4,4,4,5,5,1,1,1,2).groupedWhile(_ == _)
res0: List[List[Int]] = List(List(1), List(2, 2, 2), List(3), List(4, 4, 4), 
                             List(5, 5), List(1, 1, 1), List(2))

scala> Vector(1,2,3,4,1,2,3,1,2,1).groupedWhile(_ < _)
res1: scala.collection.immutable.Vector[scala.collection.immutable.Vector[Int]] =
  Vector(Vector(1, 2, 3, 4), Vector(1, 2, 3), Vector(1, 2), Vector(1))

এটি কাজ করে!

একমাত্র সমস্যাটি হ'ল আমাদের সাধারণভাবে অ্যারেগুলির জন্য এই পদ্ধতিগুলি উপলভ্য নয়, কারণ এটির জন্য পরপর দুটি বিহীন রূপান্তর প্রয়োজন। এটিকে ঘুরে দেখার বেশ কয়েকটি উপায় রয়েছে যার মধ্যে অ্যারেগুলির জন্য পৃথক অন্তর্নিহিত রূপান্তর লিখন, এতে ingালাই করা WrappedArrayইত্যাদি।


সম্পাদনা: অ্যারে এবং স্ট্রিংগুলির সাথে ডিল করার জন্য আমার অনুকূল দৃষ্টিভঙ্গি হ'ল কোডটিকে আরও জেনেরিক করা এবং তারপরে পুনরায় আরও নির্দিষ্ট করে দেওয়ার জন্য উপযুক্ত অন্তর্নিহিত রূপান্তরগুলি ব্যবহার করা যাতে অ্যারেগুলিও কাজ করে। এই বিশেষ ক্ষেত্রে:

class GroupingCollection[A, C, D[C]](ca: C)(
  implicit c2i: C => Iterable[A],
           cbf: CanBuildFrom[C,C,D[C]],
           cbfi: CanBuildFrom[C,A,C]
) {
  def groupedWhile(p: (A,A) => Boolean): D[C] = {
    val it = c2i(ca).iterator
    val cca = cbf()
    if (!it.hasNext) cca.result
    else {
      val as = cbfi()
      var olda = it.next
      as += olda
      while (it.hasNext) {
        val a = it.next
        if (p(olda,a)) as += a
        else { cca += as.result; as.clear; as += a }
        olda = a
      }
      cca += as.result
    }
    cca.result
  }
}

এখানে আমরা একটি অন্তর্নিহিত জুড়েছেন আমাদের একটি দেয় Iterable[A]থেকে C--for সবচেয়ে সংগ্রহের এই মাত্র পরিচয় হতে হবে (যেমন List[A]ইতিমধ্যে একটি হল Iterable[A]), কিন্তু অ্যারে জন্য এটি একটি বাস্তব অন্তর্নিহিত রূপান্তর করা হবে। এবং, ফলস্বরূপ, আমরা প্রয়োজনীয়তাটি ফেলে C[A] <: Iterable[A]রেখেছি - আমরা মূলত কেবল <%স্পষ্ট করার জন্য প্রয়োজনীয়তা তৈরি করেছি , তাই আমরা সংকলকটি এটি পূরণ করার পরিবর্তে আমরা এটি ইচ্ছামত ব্যবহার করতে পারি it এছাড়াও, আমাদের সংগ্রহ-সংগ্রহগুলি - - C[C[A]]স্থিতিশীল যে নিষেধাজ্ঞা শিথিল করে ফেলেছি তা হ'ল D[C]আমরা যা চাই তা পূরণ করতে আমরা পরে এটি পূরণ করব। যেহেতু আমরা এটি পরে পূরণ করতে যাচ্ছি, আমরা এটিকে ধাপে ধাপে স্তর স্তরের পরিবর্তে শ্রেণির স্তর পর্যন্ত রেখেছি। অন্যথায়, এটি মূলত একই।

এখন প্রশ্ন কীভাবে এটি ব্যবহার করবেন। নিয়মিত সংগ্রহের জন্য, আমরা এটি করতে পারি:

implicit def collections_have_grouping[A, C[A]](ca: C[A])(
  implicit c2i: C[A] => Iterable[A],
           cbf: CanBuildFrom[C[A],C[A],C[C[A]]],
           cbfi: CanBuildFrom[C[A],A,C[A]]
) = {
  new GroupingCollection[A,C[A],C](ca)(c2i, cbf, cbfi)
}

যেখানে এখন আমরা C[A]জন্য Cএবং C[C[A]]জন্য প্লাগ ইন D[C]। নোট করুন যে আমাদের কলটিতে সুস্পষ্ট জেনেরিক প্রকারের প্রয়োজন new GroupingCollectionতাই এটি কোন ধরণের সাথে সামঞ্জস্য রাখে তা সোজা রাখতে পারে। ধন্যবাদ implicit c2i: C[A] => Iterable[A], এটি স্বয়ংক্রিয়ভাবে অ্যারে পরিচালনা করে।

তবে অপেক্ষা করুন, যদি আমরা স্ট্রিং ব্যবহার করতে চান? এখন আমরা সমস্যায় আছি, কারণ আপনার কাছে "স্ট্রিংয়ের স্ট্রিং" থাকতে পারে না। এটি এখানে অতিরিক্ত বিমূর্তি সাহায্য করে: আমরা Dস্ট্রিংগুলি ধরে রাখতে উপযুক্ত এমন কিছু কল করতে পারি । আসুন বাছাই Vectorকরুন এবং নিম্নলিখিতগুলি করুন:

val vector_string_builder = (
  new CanBuildFrom[String, String, Vector[String]] {
    def apply() = Vector.newBuilder[String]
    def apply(from: String) = this.apply()
  }
)

implicit def strings_have_grouping(s: String)(
  implicit c2i: String => Iterable[Char],
           cbfi: CanBuildFrom[String,Char,String]
) = {
  new GroupingCollection[Char,String,Vector](s)(
    c2i, vector_string_builder, cbfi
  )
}

CanBuildFromস্ট্রিংয়ের ভেক্টরের বিল্ডিং পরিচালনা করার জন্য আমাদের একটি নতুন দরকার (তবে এটি সত্যই সহজ, যেহেতু আমাদের কেবল কল করা দরকার Vector.newBuilder[String]) এবং তারপরে আমাদের সমস্ত প্রকার পূরণ করতে হবে যাতে GroupingCollectionসংবেদনশীলভাবে টাইপ করা যায়। নোট করুন যে আমরা ইতিমধ্যে একটি [String,Char,String]ক্যানবিল্ডফর্মের চারপাশে ভাসছি, তাই চরগুলি সংগ্রহ থেকে স্ট্রিংগুলি তৈরি করা যায়।

আসুন এটি ব্যবহার করে দেখুন:

scala> List(true,false,true,true,true).groupedWhile(_ == _)
res1: List[List[Boolean]] = List(List(true), List(false), List(true, true, true))

scala> Array(1,2,5,3,5,6,7,4,1).groupedWhile(_ <= _) 
res2: Array[Array[Int]] = Array(Array(1, 2, 5), Array(3, 5, 6, 7), Array(4), Array(1))

scala> "Hello there!!".groupedWhile(_.isLetter == _.isLetter)
res3: Vector[String] = Vector(Hello,  , there, !!)

অ্যারেগুলির জন্য সমর্থন যুক্ত করতে আপনি <% ব্যবহার করতে পারেন।
বেনামে

@ নামবিহীন - কেউ সন্দেহ করবে। কিন্তু আপনি কি এই ক্ষেত্রে এটি চেষ্টা করে?
রেক্স কের

@ রেক্স: "একপর্যায়ে দু'জন অন্তর্নিহিত রূপান্তর প্রয়োজন" আমাকে স্ট্যাকওভারফ্লো / প্রশ্নগুলি মনে করিয়ে দেয় / ৩৩৩৩০৮০১/২ এখানে প্রযোজ্য?
পিটার স্মিটজ

@ পিটার - বেশ সম্ভবত! যদিও আমি <% শৃঙ্খলার উপর নির্ভর না করে সুস্পষ্ট অন্তর্নিহিত রূপান্তরগুলি লিখি।
রেক্স কের

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

29

এর হিসাবে এই কমিট এটি একটি অনেক "সমৃদ্ধ" Scala সংগ্রহ করা আরো সহজ তুলনায় এটি ছিল যখন রেক্স তার চমৎকার উত্তর দিয়েছে। সাধারণ ক্ষেত্রে এটি দেখতে এরকম দেখতে পারে,

import scala.collection.generic.{ CanBuildFrom, FromRepr, HasElem }
import language.implicitConversions

class FilterMapImpl[A, Repr](val r : Repr)(implicit hasElem : HasElem[Repr, A]) {
  def filterMap[B, That](f : A => Option[B])
    (implicit cbf : CanBuildFrom[Repr, B, That]) : That = r.flatMap(f(_).toSeq)
}

implicit def filterMap[Repr : FromRepr](r : Repr) = new FilterMapImpl(r)

যা filterMapসমস্ত ক্ষেত্রে সম্মানজনক অপারেশন যুক্ত করে "একই ফলাফলের ধরণ" GenTraversableLike,

scala> val l = List(1, 2, 3, 4, 5)
l: List[Int] = List(1, 2, 3, 4, 5)

scala> l.filterMap(i => if(i % 2 == 0) Some(i) else None)
res0: List[Int] = List(2, 4)

scala> val a = Array(1, 2, 3, 4, 5)
a: Array[Int] = Array(1, 2, 3, 4, 5)

scala> a.filterMap(i => if(i % 2 == 0) Some(i) else None)
res1: Array[Int] = Array(2, 4)

scala> val s = "Hello World"
s: String = Hello World

scala> s.filterMap(c => if(c >= 'A' && c <= 'Z') Some(c) else None)
res2: String = HW

এবং প্রশ্ন থেকে উদাহরণের জন্য, সমাধানটি এখন দেখতে দেখতে,

class GroupIdenticalImpl[A, Repr : FromRepr](val r: Repr)
  (implicit hasElem : HasElem[Repr, A]) {
  def groupIdentical[That](implicit cbf: CanBuildFrom[Repr,Repr,That]): That = {
    val builder = cbf(r)
    def group(r: Repr) : Unit = {
      val first = r.head
      val (same, rest) = r.span(_ == first)
      builder += same
      if(!rest.isEmpty)
        group(rest)
    }
    if(!r.isEmpty) group(r)
    builder.result
  }
}

implicit def groupIdentical[Repr : FromRepr](r: Repr) = new GroupIdenticalImpl(r)

নমুনা REPL অধিবেশন,

scala> val l = List(1, 1, 2, 2, 3, 3, 1, 1)
l: List[Int] = List(1, 1, 2, 2, 3, 3, 1, 1)

scala> l.groupIdentical
res0: List[List[Int]] = List(List(1, 1),List(2, 2),List(3, 3),List(1, 1))

scala> val a = Array(1, 1, 2, 2, 3, 3, 1, 1)
a: Array[Int] = Array(1, 1, 2, 2, 3, 3, 1, 1)

scala> a.groupIdentical
res1: Array[Array[Int]] = Array(Array(1, 1),Array(2, 2),Array(3, 3),Array(1, 1))

scala> val s = "11223311"
s: String = 11223311

scala> s.groupIdentical
res2: scala.collection.immutable.IndexedSeq[String] = Vector(11, 22, 33, 11)

আবার, নোট করুন যে একই ফলাফল টাইপ নীতিটি ঠিক একইভাবে পর্যবেক্ষণ করা হয়েছে যেহেতু এটি groupIdenticalসরাসরি সংজ্ঞায়িত করা হত GenTraversableLike


4
হ্যাঁ! আছে আরও বেশি ঐন্দ্রজালিক টুকরা এই ভাবে ট্র্যাক রাখতে, কিন্তু তারা সব সুন্দরভাবে মেশা! প্রতিটি অ-সংগ্রহ-শ্রেণিবদ্ধ সংগ্রহ সম্পর্কে উদ্বিগ্ন না হওয়ার জন্য স্বস্তি।
রেক্স কের

4
আমার এক-লাইন পরিবর্তন প্রত্যাখ্যান করার কারণে খুব খারাপ আইট্রেটর কৃতজ্ঞভাবে বাদ দেওয়া হয়েছে। "ত্রুটি: স্কেল কোডলিকেশন.জেনেরিক টাইপের প্রমাণ পরামিতিগুলির জন্য অন্তর্নিহিত মান খুঁজে পাওয়া যায়নি romফ্রিমার্পার [আইট্রেটার [ইন্টি]]"
পিএসপি

কোন এক-লাইনের পরিবর্তনটি অস্বীকার করা হয়েছিল?
মাইলস সাবিন


4
আমি এটিকে মাস্টার দেখি না; এটি বাষ্পীভূত হয়ে গেছে, বা ২.১০.০ পোস্টের পরে শাখায় এসেছিল বা ...?
রেক্স কের

9

এর হিসাবে এই কমিট যাদু মন্ত্র সামান্য এটা কি ছিল যখন মাইলস তার চমৎকার উত্তর দিয়েছেন থেকে পরিবর্তিত হয়।

নিম্নলিখিত কাজ করে, তবে এটি কি প্রমিত? আমি আশা করি একটি ক্যানন এটি সংশোধন করবে। (বা বরং, কামান, বড় বন্দুকগুলির মধ্যে একটি)) যদি ভিউ বাউন্ডটি একটি উপরের বাউন্ড হয় তবে আপনি অ্যারে এবং স্ট্রিংয়ের প্রয়োগ হারাবেন। এটি সীমাটি GenTraversableLike বা TraversableLike কিনা তা মনে হচ্ছে না; তবে ইসট্রাভার্সেবলাইক আপনাকে একটি জেনারেট্রসেবল লাইক দেয়।

import language.implicitConversions
import scala.collection.{ GenTraversable=>GT, GenTraversableLike=>GTL, TraversableLike=>TL }
import scala.collection.generic.{ CanBuildFrom=>CBF, IsTraversableLike=>ITL }

class GroupIdenticalImpl[A, R <% GTL[_,R]](val r: GTL[A,R]) {
  def groupIdentical[That](implicit cbf: CBF[R, R, That]): That = {
    val builder = cbf(r.repr)
    def group(r: GTL[_,R]) {
      val first = r.head
      val (same, rest) = r.span(_ == first)
      builder += same
      if (!rest.isEmpty) group(rest)
    }
    if (!r.isEmpty) group(r)
    builder.result
  }
}

implicit def groupIdentical[A, R <% GTL[_,R]](r: R)(implicit fr: ITL[R]):
  GroupIdenticalImpl[fr.A, R] =
  new GroupIdenticalImpl(fr conversion r)

নয়টি প্রাণবন্ত একটি বিড়ালকে চামড়ার একাধিক উপায় রয়েছে। এই সংস্করণটি বলছে যে একবার আমার উত্সটি একটি GenTraversableLike এ রূপান্তরিত হয়, যতক্ষণ না আমি GenTraversable থেকে ফলাফল তৈরি করতে পারি, কেবল এটি করুন। আমি আমার পুরানো প্রতিবেদনে আগ্রহী নই।

class GroupIdenticalImpl[A, R](val r: GTL[A,R]) {
  def groupIdentical[That](implicit cbf: CBF[GT[A], GT[A], That]): That = {
    val builder = cbf(r.toTraversable)
    def group(r: GT[A]) {
      val first = r.head
      val (same, rest) = r.span(_ == first)
      builder += same
      if (!rest.isEmpty) group(rest)
    }
    if (!r.isEmpty) group(r.toTraversable)
    builder.result
  }
}

implicit def groupIdentical[A, R](r: R)(implicit fr: ITL[R]):
  GroupIdenticalImpl[fr.A, R] =
  new GroupIdenticalImpl(fr conversion r)

এই প্রথম প্রয়াসে জেনারেট্রেসযোগ্য লাইকে রেপ্রের একটি কুরুচিপূর্ণ রূপান্তর অন্তর্ভুক্ত।

import language.implicitConversions
import scala.collection.{ GenTraversableLike }
import scala.collection.generic.{ CanBuildFrom, IsTraversableLike }

type GT[A, B] = GenTraversableLike[A, B]
type CBF[A, B, C] = CanBuildFrom[A, B, C]
type ITL[A] = IsTraversableLike[A]

class FilterMapImpl[A, Repr](val r: GenTraversableLike[A, Repr]) { 
  def filterMap[B, That](f: A => Option[B])(implicit cbf : CanBuildFrom[Repr, B, That]): That = 
    r.flatMap(f(_).toSeq)
} 

implicit def filterMap[A, Repr](r: Repr)(implicit fr: ITL[Repr]): FilterMapImpl[fr.A, Repr] = 
  new FilterMapImpl(fr conversion r)

class GroupIdenticalImpl[A, R](val r: GT[A,R])(implicit fr: ITL[R]) { 
  def groupIdentical[That](implicit cbf: CBF[R, R, That]): That = { 
    val builder = cbf(r.repr)
    def group(r0: R) { 
      val r = fr conversion r0
      val first = r.head
      val (same, other) = r.span(_ == first)
      builder += same
      val rest = fr conversion other
      if (!rest.isEmpty) group(rest.repr)
    } 
    if (!r.isEmpty) group(r.repr)
    builder.result
  } 
} 

implicit def groupIdentical[A, R](r: R)(implicit fr: ITL[R]):
  GroupIdenticalImpl[fr.A, R] = 
  new GroupIdenticalImpl(fr conversion r)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.