একটি সাধারণ কেস শ্রেণীর জন্য অর্ডারিং সংজ্ঞা দেওয়ার সহজ আইডোমেটিক উপায়


110

আমার কাছে সরল স্কেলা কেস শ্রেণীর উদাহরণগুলির একটি তালিকা রয়েছে এবং আমি এগুলি ব্যবহার করে অনুমানযোগ্য, ডিক্সিকোগ্রাফিক ক্রমে মুদ্রণ করতে চাই list.sorted, তবে "এর জন্য কোনও অন্তর্নিহিত আদেশ সংজ্ঞায়িত করা হয়নি ..." পেয়েছি।

কেস ক্লাসগুলির জন্য অভিধান সংক্রান্ত ক্রম সরবরাহ করে এমন কোনও অন্তর্নিহিত উপস্থিত রয়েছে কি?

কেস ক্লাসে লিক্সোগ্রাফিক অর্ডার মিক্স-ইন করার কি সরল ইডোমেটিক উপায় আছে?

scala> case class A(tag:String, load:Int)
scala> val l = List(A("words",50),A("article",2),A("lines",7))

scala> l.sorted.foreach(println)
<console>:11: error: No implicit Ordering defined for A.
          l.sorted.foreach(println)
            ^

আমি একটি 'হ্যাক' দিয়ে খুশি নই:

scala> l.map(_.toString).sorted.foreach(println)
A(article,2)
A(lines,7)
A(words,50)

8
আমি শুধু জেনেরিক সমাধানের একটি দম্পতি সঙ্গে একটি ব্লগ পোস্টে আপ লিখেছি এখানে
ট্র্যাভিস ব্রাউন 21

উত্তর:


152

আমার ব্যক্তিগত প্রিয় পদ্ধতিটি হল টিউপলসের জন্য সরবরাহিত অন্তর্নিহিত ক্রমটি ব্যবহার করা, যেমন এটি পরিষ্কার, সংক্ষিপ্ত এবং সঠিক:

case class A(tag: String, load: Int) extends Ordered[A] {
  // Required as of Scala 2.11 for reasons unknown - the companion to Ordered
  // should already be in implicit scope
  import scala.math.Ordered.orderingToOrdered

  def compare(that: A): Int = (this.tag, this.load) compare (that.tag, that.load)
}

এটি কাজ করে কারণ সঙ্গীOrdered কোনও অন্তর্নিহিত রূপান্তর সংজ্ঞা Ordering[T]দেয় Ordered[T]যা থেকে কোনও শ্রেণি প্রয়োগের সুযোগ রয়েছে Ordered। অন্তর্নিহিত অস্তিত্ব Orderingজন্য গুলি Tuples থেকে একটি রূপান্তর সম্ভব TupleN[...]করার Ordered[TupleN[...]]প্রদত্ত একটি অন্তর্নিহিত Ordering[TN]সব উপাদান বিদ্যমান নেই T1, ..., TNtuple এর, যা সবসময় ক্ষেত্রে হওয়া উচিত কারণ এটির কোনো কোনো ডেটা ধরনের উপর সাজানোর কোন জ্ঞান করে তোলে Ordering

কোনও যৌগিক বাছাই কী জড়িত যে কোনও সাজানোর দৃশ্যের জন্য টিপলসের জন্য অন্তর্নিহিত ক্রমটিপশনটি হ'ল:

as.sortBy(a => (a.tag, a.load))

যেহেতু এই উত্তরটি জনপ্রিয় হিসাবে প্রমাণিত হয়েছে আমি এটিকে আরও প্রসারিত করতে চাই, উল্লেখ করে যে নিম্নলিখিত পরিস্থিতিতেগুলির মতো সমাধানটি কিছু পরিস্থিতিতে এন্টারপ্রাইজ-গ্রেড হিসাবে বিবেচনা করা যেতে পারে:

case class Employee(id: Int, firstName: String, lastName: String)

object Employee {
  // Note that because `Ordering[A]` is not contravariant, the declaration
  // must be type-parametrized in the event that you want the implicit
  // ordering to apply to subclasses of `Employee`.
  implicit def orderingByName[A <: Employee]: Ordering[A] =
    Ordering.by(e => (e.lastName, e.firstName))

  val orderingById: Ordering[Employee] = Ordering.by(e => e.id)
}

দেওয়া হয়েছে es: SeqLike[Employee], es.sorted()নাম অনুসারে বাছাই করবে এবং es.sorted(Employee.orderingById)আইডি অনুসারে বাছাই করবে। এর কয়েকটি সুবিধা রয়েছে:

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

আপনার উদাহরণটি দুর্দান্ত! একক লাইনার এবং আমার ডিফল্ট ক্রম রয়েছে। আপনাকে অনেক ধন্যবাদ.
ya_pulser

7
উত্তরে প্রস্তাবিত কেস ক্লাসটি স্কেল ২.১০ এর অধীনে সংকলন বলে মনে হচ্ছে না। আমি কিছু অনুপস্থিত করছি?
ডোরন ইয়াাকোবি

3
@ ডোরোনইয়াাকোবি: আমিও একটি ত্রুটি পেয়েছি value compare is not a member of (String, Int)
bluenote10

1
@ জ্যাকক্র্যাকনেল ত্রুটিটি এখনও আমদানির পরেও রয়েছে (স্কেলা ২.১০.৪)। সংকলনের সময় ত্রুটি দেখা দেয় তবে আইডিইতে পতাকাঙ্কিত হন না। (আকর্ষণীয়ভাবে, এটি আরপিএলে সঠিকভাবে কাজ করে)। যাদের এই সমস্যা রয়েছে তাদের জন্য, এই এসও উত্তরের সমাধানটি কাজ করে (যদিও উপরের মত মার্জিত নয়)। এটি যদি বাগ হয় তবে কেউ কি এটি রিপোর্ট করেছে?
Jus12

2
ফিক্স: অর্ডারিংয়ের ক্ষেত্রটি টানছে না, আপনি এটিকে স্পষ্টভাবে টানতে পারেন তবে কেবল অর্ডারিং সরাসরি ব্যবহার করা যথেষ্ট সহজ: ডিফ তুলনা (যে: এ) = অর্ডারিং।টুপল 2 [স্ট্রিং, স্ট্রিং] .কম্পের (টিপল) ), tuple (that))
ব্র্যান্ডন

46
object A {
  implicit val ord = Ordering.by(unapply)
}

এটির সুবিধাটি রয়েছে যে যখনই এ পরিবর্তন হয় এটি স্বয়ংক্রিয়ভাবে আপডেট হয়। তবে, এ এর ​​ক্ষেত্রগুলি যাতে ক্রম দ্বারা আদেশটি সেগুলি ব্যবহার করবে তা স্থাপন করা দরকার।


দেখতে দুর্দান্ত, তবে কীভাবে এটি ব্যবহার করবেন তা আমি বুঝতে পারি না, আমি পেয়েছি:<console>:12: error: not found: value unapply
zbstof

29

সংক্ষিপ্তসার হিসাবে, এটি করার জন্য তিনটি উপায় রয়েছে:

  1. একজাতীয় বাছাইয়ের জন্য .Sortowland হিসাবে দেখানো হয়েছে, অনুসারে বাছাই পদ্ধতি দ্বারা
  2. অর্ডারযুক্ত বৈশিষ্ট্য সহ প্রসারিত কেস ক্লাসটি পুনরায় ব্যবহারের জন্য, যেমন @ কীথ বলেছিল।
  3. একটি কাস্টম ক্রম সংজ্ঞায়িত করুন। এই সমাধানটির সুবিধা হ'ল আপনি অর্ডারগুলি পুনরায় ব্যবহার করতে পারেন এবং একই শ্রেণীর উদাহরণগুলি বাছাই করার একাধিক উপায় থাকতে পারে:

    case class A(tag:String, load:Int)
    
    object A {
      val lexicographicalOrdering = Ordering.by { foo: A => 
        foo.tag 
      }
    
      val loadOrdering = Ordering.by { foo: A => 
        foo.load 
      }
    }
    
    implicit val ord = A.lexicographicalOrdering 
    val l = List(A("words",1), A("article",2), A("lines",3)).sorted
    // List(A(article,2), A(lines,3), A(words,1))
    
    // now in some other scope
    implicit val ord = A.loadOrdering
    val l = List(A("words",1), A("article",2), A("lines",3)).sorted
    // List(A(words,1), A(article,2), A(lines,3))

আপনার প্রশ্নের উত্তর দেওয়া স্কেলের অন্তর্ভুক্ত এমন কোনও স্ট্যান্ডার্ড ফাংশন রয়েছে যা তালিকার মতো ম্যাজিক করতে পারে ((2,1), (1,2)) বাছাই করা হয়েছে

একটি সেট আছে পূর্বনির্ধারিত অর্ডারের , যেমন স্ট্রিংয়ের জন্য, 9 টি আরটি পর্যন্ত এবং আরও অনেক কিছু।

কেস ক্লাসগুলির জন্য এ জাতীয় কোনও জিনিস বিদ্যমান নেই, যেহেতু ক্ষেত্রের নামগুলি একটি অগ্রাধিকার হিসাবে জানা যায় না (কমপক্ষে ম্যাক্রো যাদু ছাড়াই) এবং আপনি কেস ক্লাসের ক্ষেত্রগুলি ব্যতীত অন্যভাবে অ্যাক্সেস করতে পারবেন না given নাম / পণ্য পুনরুক্তি ব্যবহার করে।


উদাহরণের জন্য আপনাকে অনেক ধন্যবাদ। আমি অন্তর্নিহিত ক্রমটি বোঝার চেষ্টা করব।
ya_pulser

8

unapplyসহচর বস্তুর পদ্ধতি একটি আপনার ক্ষেত্রে বর্গ থেকে একটি রূপান্তর প্রদান করে Option[Tuple], যেখানে Tupletuple ক্ষেত্রে ক্লাসের প্রথম আর্গুমেন্ট তালিকা সংশ্লিষ্ট নয়। অন্য কথায়:

case class Person(name : String, age : Int, email : String)

def sortPeople(people : List[Person]) = 
    people.sortBy(Person.unapply)

6

সাজ্টবাই পদ্ধতিটি এটি করার একটি সাধারণ উপায় হবে, যেমন ( tagক্ষেত্রের উপর বাছাই ):

scala> l.sortBy(_.tag)foreach(println)
A(article,2)
A(lines,7)
A(words,50)

ক্ষেত্রে শ্রেণিতে 3+ ক্ষেত্রের ক্ষেত্রে কী করবেন? l.sortBy( e => e._tag + " " + e._load + " " + ... )?
ya_pulser

যদি ব্যবহার করে থাকেন sortBy, তবে হ্যাঁ, তা হয়, বা শ্রেণিতে / (যেমন _.toString, বা আপনার নিজস্ব লেক্সোগ্রাফিকভাবে-উল্লেখযোগ্য কাস্টম পদ্ধতি বা বাহ্যিক ফাংশন) উপযুক্ত ফাংশন যুক্ত / ব্যবহার করুন ।
শ্যাডোল্যান্ডস

স্ক্যালায় এমন কোনও স্ট্যান্ডার্ড ফাংশন অন্তর্ভুক্ত রয়েছে List((2,1),(1,2)).sortedযা কেস ক্লাসের অবজেক্টগুলির মতো যাদু করতে পারে? নামযুক্ত টিপলস (কেস ক্লাস == নামযুক্ত টিপল) এবং সাধারণ টিউপসগুলির মধ্যে আমি কোনও বড় পার্থক্য দেখছি না।
ya_pulser

এই লাইনের সাথে আমি যে নিকটে পৌঁছতে পারি তা হ'ল সঙ্গী অবজেক্টের অযোগ্য প্রয়োগ পদ্ধতিটি ব্যবহার করার জন্য Option[TupleN], তারপরে ফোন getকরুন: l.sortBy(A.unapply(_).get)foreach(println)যা সম্পর্কিত টিপলটিতে প্রদত্ত ক্রমটি ব্যবহার করে, তবে এটি কেবল আমি উপরে প্রকাশিত সাধারণ ধারণার একটি স্পষ্ট উদাহরণ is ।
শ্যাডোল্যান্ডস

5

আপনি যেহেতু কেস ক্লাস ব্যবহার করেছেন আপনি এই জাতীয় অর্ডার দিয়ে প্রসারিত করতে পারেন :

case class A(tag:String, load:Int) extends Ordered[A] { 
  def compare( a:A ) = tag.compareTo(a.tag) 
}

val ls = List( A("words",50), A("article",2), A("lines",7) )

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