Мне нужно реализовать класс, в котором в основном содержится ключ и пара значений, где значение представляет собой последовательность кортежей. Этот кортеж содержит объект SynthesizedMetricTag
и параметр типа A с привязкой к контексту Numeric
, поэтому эффективно последовательность k/v, где v должно быть числом.Слияние двух коллекций с различными параметрами типа в Scala
case class Cohort[A : Numeric](index:Any,values:Seq[(SynthesizedMetricTag,A)])
Проблема возникает, когда мне нужно реализовать функцию, которая объединяет два экземпляра этого класса. Более конкретно, проблема возникает, когда мне приходится объединять seq типа A с seq типа B. Оба типа имеют связанный с Numeric
контекст, поэтому идея заключается в том, что в конце я получаю Cohort[C]
, который соответствует привязке к контексту и объединяет все пары K/V последовательностей типа A
и B
без повторения любого ключа.
case class Cohort[A : Numeric](index:Any,values:Seq[(SynthesizedMetricTag,A)]) {
def merge[B : Numeric, C:Numeric](that:Cohort[B]):Cohort[C] =
if(this.index != that.index) throw new Exception("Unable to merge Cohorts. Criteria is not the same")
else {
val b = new ArrayBuffer[(SynthesizedMetricTag,C)]()
val seen = new mutable.HashSet[SynthesizedMetricTag]()
for (x <- this.values; y <- that.values){
if(!seen(x._1)){
b+= x
seen += x._1
}
if(!seen(y._1)){
b+= y
seen += y._1
}
}
Cohort(this.index,b.toSeq)
}
}
Конечно, этот код бросает следующие ошибки:
[error] /Users/ernestrc/dev/everreach/operations-api/src/main/scala/everreach/operations/model/Cohort.scala:14: type mismatch;
[error] found : (everreach.operations.model.SynthesizedMetricTag, A)
[error] required: (everreach.operations.model.SynthesizedMetricTag, C)
[error] b+= x
[error] ^
[error] /Users/ernestrc/dev/everreach/operations-api/src/main/scala/everreach/operations/model/Cohort.scala:18: type mismatch;
[error] found : (everreach.operations.model.SynthesizedMetricTag, B)
[error] required: (everreach.operations.model.SynthesizedMetricTag, C)
[error] b+= y
Так что я попытался следующие:
case class Cohort[A : Numeric](index:Any,values:Seq[(SynthesizedMetricTag,A)]) {
def merge[B : Numeric, C:Numeric](that:Cohort[B]):Cohort[C] =
if(this.index != that.index) throw new Exception("Unable to merge Cohorts. Criteria is not the same")
else {
val b = new ArrayBuffer[(SynthesizedMetricTag,C)]()
val seen = new mutable.HashSet[SynthesizedMetricTag]()
for (x <- this.values; y <- that.values){
if(!seen(x._1)){
b+= x.asInstanceOf[(SynthesizedMetricTag,C)]
seen += x._1
}
if(!seen(y._1)){
b+= y.asInstanceOf[(SynthesizedMetricTag,C)]
seen += y._1
}
}
Cohort(this.index,b.toSeq)
}
}
И это компилируется, но я уверен, что это не идиоматический способ сделать это. Вы, ребята, знаете, как решить эту проблему?
EDIT
Алексей сделал хороший момент:
Что именно вы хотите, если, например, A - Double, B - Long, а C - Byte?
Ну C
должен быть передан в качестве параметра типа, так как в противном случае компилятор не знает, что C
, поэтому я хотел бы A
и B
быть преобразованы в C
. Но я действительно хочу, чтобы никогда не терять информацию. Так что если, например, A
является Int
и B
является Float
, я хочу A
быть преобразованы в Float
и объединить оба A
и B
в коллекцию C
(Float
).
Конечно, эта иерархия не существует, не так ли? Вот почему мне нужно абстрагировать тип результата в C
и вручную передать его как параметр типа.
Что именно вы хотите, чтобы произошло, если, например, 'A' -' Double', 'B'' '' '' '' '' '' '' Byte'? –
Ну 'C' нужно передать как параметр типа, потому что иначе компилятор не знает, что такое' C', поэтому я хотел бы, чтобы 'A' и' B' были преобразованы в 'C'. Но я действительно хочу, чтобы никогда не терять информацию. Итак, если, например, 'A' является' Int' и 'B' является' Float', я хочу, чтобы 'A' был преобразован в' Float' и объединил как 'A', так и' B' в коллекцию 'C '(' Float'). Конечно, эта иерархия не существует, не так ли? Вот почему мне нужно абстрагировать тип результата на C и определить его вручную. – ernestRC