根据Scala中的特定条件压缩两个列表

时间:2019-07-24 10:02:39

标签: scala functional-programming

我有两个已定义的案例类和两个列表,如下面的代码。

case class Person(name: String, company: String, rank: Int, id: Long)

case class Employee(company: String, rank: Int, id: Long)
val persons = List(Person("Tom", "CompanyA", 1, null), Person("Jenny", "CompanyB", 1, null), Person("James", "CompanyA", 2, null))

val employees = List(Employee("CompanyA", 1, 1001), Employee("CompanyB", 1, 1002), Employee("CompanyA", 2, 1003))

由于companyrank的组合是唯一的,所以我想使用employees中的信息,以便可以将两个列表合并为以下列表(“人”列表ID已满)。

[Person("Tom", "CompanyA", 1, 1001), Person("Jenny", "CompanyB", 1, 1002), Person("James", "CompanyA", 2, 1003)]

我试图这样实现:

zipBasedOnCondition(persons, employees, (person, employee) => person.name == employee.name && person.rank === employee.rank)

但是,我未能提出实现zipBasedOnCondition功能的解决方案

有什么办法可以合并两个列表?

4 个答案:

答案 0 :(得分:3)

您想要的可以通过以下方式实现:

for {
  person <- persons
  employee <- employees
  if person.name == employee.name && person.rank === employee.rank
} yield person.copy(id = employee.id)

它的时间复杂度为O(persons.size * employees.size),但是由于List无法保证内部事物被排序(尤其是要根据您要比较的事物进行排序),因此您无法对其进行优化。

如果需要,您可以对其进行修改,以使其采用可能的第一个配对,尽管这超出了“带条件的zip”的范围。

答案 1 :(得分:0)

我仍在寻找更好的解决方案...但这应该可行:

def f(c: String): Option[Employee] = employees.filter(_.company == c).headOption

for {
  p <- persons
  e <- f(p.company)
} yield {
  p.copy(id = e.id)
}

答案 2 :(得分:0)

这将是一种非常通用的方法:

def zipBasedOnCondition[A, B, C](as: List[A], bs: List[B], pred: (A, B) => Boolean, f: (A, B) => C): List[C] = {
    as.map(a => f(a, bs.filter(b => pred(a, b)).head))
}

然后您可以这样称呼它:

zipBasedOnCondition[Person, Employee, Person](persons, employees, (p, e) => p.name == e.name && p.rank == e.rank, (a, b) => a.copy(id = b.id))

zipBasedOnCondition的实现将需要改进,因为它假定每个人对象都有一个对应的员工对象。

答案 3 :(得分:0)

您将在Person类中提供id字段作为必填字段,并在person列表中提供空值,这将产生错误。 首先,让我们更正您的Person类。

 case class Person(name: String, company: String, rank: Int, id: Long = 0) 

现在,解决您的问题。

 def combineList( list1: List[Person], list2: List[Employee]): List[(Person)] = {
  (for{
   a <- list1
   b <- list2
   if (a.company == b.company && a.rank == b.rank)
  } yield (a.copy(id = b.id)))
 }

输出

List(Person(Tom,CompanyA,1,1001), Person(Jenny,CompanyB,1,1002), Person(James,CompanyA,2,1003))