У меня есть список простых экземпляров класса case scala, и я хочу напечатать их в предсказуемом, лексикографическом порядке, используя list.sorted
, но получаю сообщение «Неявный порядок определен для ...».
Существует ли неявный, обеспечивающий лексикографический порядок для классов case?
Есть ли простой идиоматический способ смешать лексикографический порядок с классом case?
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)
scala
sorting
case-class
ya_pulser
источник
источник
Ответы:
Мой личный любимый метод - использовать предоставленный неявный порядок для кортежей, поскольку он ясный, краткий и правильный:
Это работает, потому что сопутствующий
Ordered
объект определяет неявное преобразование изOrdering[T]
в,Ordered[T]
которое входит в область действия любой реализации классаOrdered
. Наличие неявногоOrdering
s дляTuple
s позволяет преобразовать изTupleN[...]
вOrdered[TupleN[...]]
при условии, что неявноеOrdering[TN]
существует для всех элементовT1, ..., TN
кортежа, что всегда должно иметь место, потому что нет смысла сортировать по типу данных с номеромOrdering
.Неявный порядок для кортежей - это ваш путь для любого сценария сортировки, включающего составной ключ сортировки:
Поскольку этот ответ оказался популярным, я хотел бы расширить его, отметив, что решение, подобное приведенному ниже, при некоторых обстоятельствах может считаться корпоративным ™:
Учитывая
es: SeqLike[Employee]
,es.sorted()
будет сортировка по имени иes.sorted(Employee.orderingById)
сортировка по идентификатору. У этого есть несколько преимуществ:Ordering
, поэтому упорядочивание напрямую исключает неявное преобразование в большинстве случаев.источник
value compare is not a member of (String, Int)
.Преимущество этого заключается в том, что он обновляется автоматически при изменении A. Но поля A должны быть размещены в том порядке, в котором они будут использоваться при упорядочении.
источник
<console>:12: error: not found: value unapply
Подводя итог, есть три способа сделать это:
Определите индивидуальный заказ. Преимущество этого решения в том, что вы можете повторно использовать упорядочения и иметь несколько способов сортировки экземпляров одного и того же класса:
Отвечая на ваш вопрос Есть ли в Scala какая-либо стандартная функция, которая может творить чудеса, например List ((2,1), (1,2)). Sorted
Существует набор предопределенных порядков , например, для String, кортежей до 9 арностей и так далее.
Такой вещи не существует для классов case, так как это непросто откатить, учитывая, что имена полей неизвестны априори (по крайней мере, без магии макросов), и вы не можете получить доступ к полям класса case другим способом, кроме имя / использование итератора продукта.
источник
unapply
Метод объекта - компаньон обеспечивает преобразование из вашего случая класса кOption[Tuple]
, гдеTuple
есть кортеж , соответствующий первого список аргументов класса дела. Другими словами:источник
Метод sortBy может быть одним из типичных способов сделать это, например (сортировка по
tag
полю):источник
l.sortBy( e => e._tag + " " + e._load + " " + ... )
?sortBy
, то да, либо это, либо добавить / использовать подходящую функцию в / в классе (например_.toString
, или ваш собственный лексографически значимый пользовательский метод или внешняя функция).List((2,1),(1,2)).sorted
с объектами класса case? Я не вижу большой разницы между именованными кортежами (case class == named tuple) и простыми кортежами.Option[TupleN]
, а затем вызвать егоget
:,l.sortBy(A.unapply(_).get)foreach(println)
который использует предоставленный порядок в соответствующем кортеже, но это просто явный пример общей идеи, которую я привожу выше .Поскольку вы использовали класс case, вы можете расширить его с помощью Ordered следующим образом:
источник