Если вы хотите сделать это с помощью Shapeless, я бы настоятельно предложил определить класс пользовательского типа, который обрабатывает сложную часть и позволяет сохранить этот материал отдельно от остальной части вашей логики.
В этом случае это похоже на сложную часть того, что вы пытаетесь сделать, это получить сопоставление от имен полей до длин строк для всех членов класса String
. Вот класс типа, который делает это:
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)
}
}
Это выглядит сложное, но как только вы начинаете работать с бесформенным немного вы научитесь писать такие вещи во сне.
Теперь вы можете написать логику вашей работы относительно простым способом:
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)))
}
}
А затем (с учетом rows
, как это определено в вопросе):
scala> maxStringLengths(rows).foreach(println)
(bankCharges,3)
(overTime,3)
(mgmtFee,5)
(email,9)
(copyOfVisa,3)
Это будет работать для абсолютно любой случай класс.
Если это одноразовая вещь, вы можете использовать отражение во время выполнения, или вы можете использовать подход Poly1
в ответе Джованни Капораретти - он менее общий, и он смешивает различные части решения так, как я не предпочитают, но он должен работать нормально. Если это то, что вы делаете много, я бы предложил подход, который я здесь привел.
Большое спасибо.Я должен вернуться к этому, когда я освоил Безжизненное! –
Не ждите до тех пор! Я не уверен, что кто-то овладел безжизненным! –
приятно, гораздо лучше, чем у меня! –