Nano Hash - криптовалюты, майнинг, программирование

Создайте метод обобщения без потери типов

у нас есть

private def insertUpdateDeleteFormDsList(dsList : List[FormDefinitionDataSourceRequestModel])(implicit formDefId:Int,subject:Subject,session: Session) : (List[(Int,Int)],Seq[FormDefinitionDataSourceRequestModel],Seq[FormDefinitionDataSourceRequestModel]) = {
val incomingIds = dsList.map( ds => (ds.dataSourceId,ds.dsTypeId) )

val existingIds = formDefinitionDatasources.filter(_.tenantId === subject.tenantId).filter(_.formDefId === formDefId).map( ds => (ds.dataSourceId,ds.dataSourceTypeId) ).list

val idsForDeletion = existingIds diff incomingIds
val idsForInsertion = incomingIds diff existingIds
val idsForUpdate = existingIds diff idsForDeletion


val insertList = dsList.flatMap{ t => idsForInsertion collectFirst{ case (dsId,dsType) if(dsId == t.dataSourceId && dsType == t.dsTypeId)=> t} }
val updateList = dsList.flatMap{t=>idsForUpdate collectFirst {case (dsId,dsType) if(dsId == t.dataSourceId && dsType == t.dsTypeId)=> t}}

(idsForDeletion,updateList,insertList)

}

И другие подобные методы, как

private def insertUpdateDelDataInstances(instances: List[Instance])(implicit subject: Subject, session: Session): (Seq[Instance], Seq[Instance], Seq[Instance]) = {
val incomingIds = instances.map(_.id)
val existingIds = dataSourceInstanceNew.filter(_.tenantId === subject.tenantId).map(_.id).list
val idsForDeletion = existingIds diff incomingIds
val idsForInsertion = incomingIds diff existingIds
val idsForUpdate = existingIds diff idsForDeletion

val deleteList = instances.flatMap{ t => idsForDeletion collectFirst{ case id if(id == t.id)=> t} }
val insertList = instances.flatMap{ t => idsForInsertion collectFirst{ case id if(id == t.id)=> t} }
val updateList = instances.flatMap{t=>idsForUpdate collectFirst {case id if(id === t.id)=> t}}
(deleteList,updateList,insertList)
}

Подобные методы встречаются и в других местах. Каждый раз List[T] будет передаваться в качестве аргумента метода, где T всегда будет case class. теперь то, как создается val incomingIds, зависит от конкретных атрибутов case class.

Мы хотим создать обобщенную функцию, которая может принимать List[T] и, возможно, incomingIds и возвращать желаемый кортеж, чтобы каждый раз не писать одинаково выглядящий шаблон.

Если бы логика заключалась в том, чтобы «всегда» использовать атрибут id T case class, то я мог бы легко создать родителя trait с id и смешать все case classes с чертой, но здесь это не тот случай. подготовка val incomingIds зависит от разных атрибутов case class в зависимости от того, откуда в коде они вызываются.

Иллюстрация ниже

def generalizedInsertUpdateDeleteList[T](data:List[T],incomingIds:List[Int], existingIds:List[Int] )(implicit subject: Subject, session:Session) = {
val idsForDeletion = existingIds diff incomingIds
val idsForInsertion = incomingIds diff existingIds
val idsForUpdate = existingIds diff idsForDeletion

/*
//what's the best way to generalize comparison inside  collectFirst?
//to use case class attribute names from `T`. Was thinking if Structural type can help but not sure if that
//can quite work unless there is a way to pass in arguments in a structural type? 


val deleteList = data.flatMap{ t => idsForDeletion collectFirst{ case id if(id == t.id)=> t} }
val insertList = data.flatMap{ t => idsForInsertion collectFirst{ case id if(id == t.id)=> t} }
val updateList = data.flatMap{ t => idsForUpdate collectFirst {case id if(id === t.id)=> t}}
*/

Может ли shapeless помочь здесь, если нет другого более чистого способа добиться этого с использованием стандартных API-интерфейсов scala/scalaz?

27.07.2015

Ответы:


1

Вы можете создать класс типов с PartialFunction, который можно использовать внутри collectFirst.

trait IUD[T, IdType] {
  // returns a partial function which will be used in collectFirst
  def collectId(t: T): PartialFunction[IdType, T]
}

Мы можем создать IUD экземпляра для ваших двух методов:

// I chose (Long, Long) as type of (ds.dataSourceId,ds.dsTypeId) 
type FormModel = FormDefinitionDataSourceRequestModel
implicit object FormModelIUD extends IUD[FormModel, (Long, Long)] {
  def collectId(t: FormModel): PartialFunction[(Long, Long), FormModel] = {
    case (dsId,dsType) if(dsId == t.dataSourceId && dsType == t.dsTypeId) => t
  }
}

implicit object InstanceIUD extends IUD[Instance, Int] {
  def collectId(t: Instance): PartialFunction[Int, Instance] = {
    case id if id == t.id => t
  }
}

Мы можем использовать класс типа IUD в вашем методе generalizedInsertUpdateDeleteList:

def generalizedIUDList[T, IdType](
  data: List[T], incomingIds: List[IdType], existingIds: List[IdType]
)(implicit 
  subject: Subject, session: Session, iud: IUD[T, IdType]
) = {
  val idsForDeletion = existingIds diff incomingIds
  val idsForInsertion = incomingIds diff existingIds
  val idsForUpdate = existingIds diff idsForDeletion

  def filterIds(ids: List[IdType]) = 
    data.flatMap(instance => ids collectFirst(iud.collectId(instance)) )

  val deleteList = filterIds(idsForDeletion)
  val insertList = filterIds(idsForInsertion)
  val updateList = filterIds(idsForUpdate)

  (deleteList,updateList,insertList)
} 
27.07.2015

2

Записи Shapeless обеспечивают типобезопасный способ абстрагирования над классами case с конкретным именем члена. Например:

import shapeless._, ops.record.Selector

def getId[A, R <: HList](a: A)(implicit
  gen: LabelledGeneric.Aux[A, R],
  sel: Selector[R, Witness.`'id`.T]
): sel.Out = sel(gen.to(a))

А потом:

scala> case class Foo(id: String)
defined class Foo

scala> case class Bar(id: Int, name: String)
defined class Bar

scala> getId(Foo("12345"))
res0: String = 12345

scala> getId(Bar(123, "bar"))
res1: Int = 123

Если вам нужно ограничить тип члена id, вы можете использовать Selector.Aux:

def getIntId[A, R <: HList](a: A)(implicit
  gen: LabelledGeneric.Aux[A, R],
  sel: Selector.Aux[R, Witness.`'id`.T, Int]
): Int = sel(gen.to(a))

Теперь getIntId(Bar(123, "bar")) скомпилируется, а getIntId(Foo("12345")) нет.

27.07.2015

3

collectFirst принимает PartialFunction, в вашем случае PartialFunction[Int, T] я думаю?

Вы можете передать частичные функции в качестве параметров вашему методу generalizedInsertUpdateDeleteList, тогда только их нужно будет определять каждый раз.

27.07.2015
Новые материалы

Кластеризация: более глубокий взгляд
Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

Как написать эффективное резюме
Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

Частный метод Python: улучшение инкапсуляции и безопасности
Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

Как я автоматизирую тестирование с помощью Jest
Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..