Wenn Sie so etwas mit Shapeless machen möchten, empfehle ich Ihnen, eine benutzerdefinierte Typklasse zu definieren, die den komplizierten Teil behandelt und Ihnen erlaubt, diese Dinge vom Rest Ihrer Logik zu trennen.
In diesem Fall klingt es nach dem kniffligen Teil dessen, was Sie gerade versuchen, die Zuordnung von Feldnamen zu String-Längen für alle String
Mitglieder einer Fallklasse zu bekommen. Hier ist eine Art Klasse, die das tut:
import shapeless._, shapeless.labelled.FieldType
trait StringFieldLengths[A] { def apply(a: A): Map[String, Int] }
object StringFieldLengths extends LowPriorityStringFieldLengths {
implicit val hnilInstance: StringFieldLengths[HNil] =
new StringFieldLengths[HNil] {
def apply(a: HNil): Map[String, Int] = Map.empty
}
implicit def caseClassInstance[A, R <: HList](implicit
gen: LabelledGeneric.Aux[A, R],
sfl: StringFieldLengths[R]
): StringFieldLengths[A] = new StringFieldLengths[A] {
def apply(a: A): Map[String, Int] = sfl(gen.to(a))
}
implicit def hconsStringInstance[K <: Symbol, T <: HList](implicit
sfl: StringFieldLengths[T],
key: Witness.Aux[K]
): StringFieldLengths[FieldType[K, String] :: T] =
new StringFieldLengths[FieldType[K, String] :: T] {
def apply(a: FieldType[K, String] :: T): Map[String, Int] =
sfl(a.tail).updated(key.value.name, a.head.length)
}
}
sealed class LowPriorityStringFieldLengths {
implicit def hconsInstance[K, V, T <: HList](implicit
sfl: StringFieldLengths[T]
): StringFieldLengths[FieldType[K, V] :: T] =
new StringFieldLengths[FieldType[K, V] :: T] {
def apply(a: FieldType[K, V] :: T): Map[String, Int] = sfl(a.tail)
}
}
Das sieht kompliziert, aber sobald Sie anfangen zu arbeiten mit Shapeless ein bisschen Sie lernen, diese Art der Sache im Schlaf zu schreiben.
Jetzt können Sie die Logik Ihres Betriebs in einer relativ einfachen Art und Weise schreiben:
def maxStringLengths[A: StringFieldLengths](as: List[A]): Map[String, Int] =
as.map(implicitly[StringFieldLengths[A]].apply).foldLeft(
Map.empty[String, Int]
) {
case (x, y) => x.foldLeft(y) {
case (acc, (k, v)) =>
acc.updated(k, acc.get(k).fold(v)(accV => math.max(accV, v)))
}
}
Und dann (bei rows
wie in der Frage festgelegt):
scala> maxStringLengths(rows).foreach(println)
(bankCharges,3)
(overTime,3)
(mgmtFee,5)
(email,9)
(copyOfVisa,3)
Dies wird für absolut arbeiten Jedenfalls Klasse. Wenn das eine einmalige Sache ist, können Sie auch die Laufzeitreflexion verwenden, oder Sie könnten den Ansatz Poly1
in Giovanni Caporaletti's Antwort verwenden - es ist weniger allgemein gehalten und es vermischt die verschiedenen Teile der Lösung in einer Weise, die ich nicht bevorzugen, aber es sollte gut funktionieren. Wenn Sie jedoch viel tun, würde ich Ihnen den Ansatz vorschlagen, den ich hier gegeben habe.
Vielen Dank.Ich muss darauf zurückkommen, wenn ich Shapeless beherrsche! –
Warten Sie nicht bis dann! Ich bin mir nicht sicher, ob jemand Shapeless beherrscht! –
schön, viel besser als meins! –