继续Scala学习曲线
我有两个对象列表。我需要将这些列表合并到一个列表中,同时应用具有匹配削减的逻辑。
因此,例如,以下是两个列表:
case class test(int: Int, str: String)
val obj1 = test(1, "one")
val obj2 = test(2, "two")
val list1 = List(obj1, obj2)
val obj3 = test(2, "Another two")
val obj4 = test(4, "four")
val list2 = List(obj1, obj2)
我需要的是:
List(test(1, "one old"), test(2, "Another two updated"), test(4, "four new"))
粗略地说,我可以用老式的方式迭代所有元素,并在那里进行所有转换,但这不是" Scala方式" (我猜)。
我尝试用foldLeft
接近它,但卡住了。以下是我的工作:
list1.foldLeft(list2) { (a:test, b:test) =>
b.int match {
case a.int => {
//Apply logic and create new object
}
}
}
更新 现在我分两步完成:
var tasks : Seq[ChecklistSchema.Task] = left.tasks.map((task:ChecklistSchema.Task) =>
right.tasks.find(t => t.groupId == task.groupId) match {
case Some(t: ChecklistSchema.Task) => t
case _ => {
task.status match {
case TaskAndValueStatus.Active => task.copy(status = TaskAndValueStatus.Hidden)
case _ => task
}
}
}
)
tasks = tasks ++ right.tasks.filter((t:ChecklistSchema.Task) => !tasks.contains(t))
必须有更好的方法!
谢谢,
答案 0 :(得分:2)
*假设val list2 = List(obj3, obj4)
。
以下是我的方法:
breakOut
此处指示编译器使用最合适的工厂构建它。更多信息https://stackoverflow.com/a/7404582/4402547)applyLogic
决定将什么称为不久的测试("新"或"更新")groupBy
放在索引上,applyLogic
和排序(可选)。 def merge(left: List[Test], right: List[Test]) = {
val old = list1.map(t => Test(t.int, t.str+" old"))
val l2Map = list2.map(t => (t.int -> t)) (breakOut): Map[Int, Test]
def applyLogic(idx: Int, tests: List[Test]): Test = {
tests.size match {
case 1 => {
val test = tests.head
if(l2Map.contains(test.int)) Test(test.int, test.str + " new") else test
}
case 2 => {
val updated = tests(1)
Test(updated.int, updated.str+" updated")
}
}
}
(old ++ list2).groupBy(t => t.int).map(f => applyLogic(f._1, f._2)).toList.sortBy((t => t.int))
}
val left = List(Test(1, "one"), Test(2, "two"))
val right = List(Test(2, "Another two"), Test(4, "four"))
val result = List(Test(1, "one old"), Test(2, "Another two updated"), Test(4, "four new"))
assert(merge(left, right) == result)
答案 1 :(得分:1)
我不知道这个解决方案是否是“Scala方式”,但它正在使用foldLeft
。
case class Test(a: Int, b: String) {
def labeled(label: String) = copy(b = b + " " + label)
}
def merge(left: List[Test], right: List[Test]) = {
val (list, updated) = left.foldLeft((List[Test](), Set[Int]())) { case ((acc, founded), value) =>
right.find(_.a == value.a) match {
case Some(newValue) => (newValue.labeled("updated") :: acc, founded + value.a)
case None => (value.labeled("old") :: acc, founded)
}
}
list.reverse ::: right.filterNot(test => updated(test.a)).map(_.labeled("new"))
}
val left = List(Test(1, "one"), Test(2, "two"))
val right = List(Test(2, "Another two"), Test(4, "four"))
val result = List(Test(1, "one old"), Test(2, "Another two updated"), Test(4, "four new"))
assert(merge(left, right) == result)
答案 2 :(得分:0)
(list1 ++ (list2.map(l => l.copy(str = l.str + " new")))).groupBy(_.int).map(
l =>
if (l._2.size >= 2) {
test(l._2(0).int, "Another two updated")
} else l._2(0)
)
地图更新新值并使用 groupBy 更新不同值