【问题标题】:how to merge a list's element where every list element has three tuples?如何合并每个列表元素都有三个元组的列表元素?
【发布时间】:2020-05-22 18:56:26
【问题描述】:

我有这个:

List(List("King",List("134"),"USA"),List("King",List("151","130"),"USA"))

我终于想要这个了:

List("King",List("134","151","130"),"USA") 

【问题讨论】:

  • 你试过什么?你能分享你的一些努力(代码)吗?
  • List("King",List("151","130"),"USA") 这太可怕了。不要这样做。 Scala 会将其转换为最近的共同祖先 Any 在这种情况下,您实际上将无法对它做任何事情
  • 您需要提供更多示例。例如,如果内部列表的头部是“KING”而尾部是“AUS”,则不清楚应该发生什么。
  • 我希望如果两个元素具有相同的头部(国王)和尾部(美国),它们的列表主体应该合并。
  • 既然你在问题标题中说了三个元组,但实际上在正文中使用了List,你能澄清一下吗?它的意思是列表中的 3 元组还是正确的方式?

标签: list scala merge tuples


【解决方案1】:

对于这个确切的用例,您可以使用Pattern Matching

val doubleList = List(List("King",List("134"),"USA"), List("King",List("151","130"),"USA"))
doubleList match {
  case (a :: (b:List[_]) :: c :: _) :: (_ :: (d:List[_]) :: _) :: _ => a :: (b ++ d) :: c :: Nil
  case other => println(s"Not expected: $other")
}

如您所见,这不是很漂亮,但如果有更好的名字,它可能对您有用。

这里有一些解释:

  • a::b::c表示一个List,其中a和b是前两个元素,c是其余元素(尾)

  • _ 是您不感兴趣的值,在我们的例子中是尾部和列表的类型。

  • 其余的组成您的列表,结果连接两个子列表。

结果如预期:

List(King, List(134, 151, 130), USA)

如 cmets 中所述,如果可以,您应该更改数据结构。

这样就容易多了。例如:

case class MyObj(name: String, indices: List[String], country: String) {

  def merge(other: MyObj): MyObj =
     copy(indices = indices ++ other.indices)
}

val obj1 = MyObj("King",List("134"),"USA")
obj1.merge(MyObj("King",List("151","130"),"USA"))

这样更好读。

更新:评论的解决方案:

您可以使用groupBy,然后使用flatMap 连接内部列表:

 st.groupBy(e => (e._1, e._3))   // -> Map((COOK,ENG) -> List((COOK,List(100),ENG), ...)
    .map{ case ((n, c), list) => (n, list.flatMap(_._2), c)}
    .toList
    .sortBy(_._1)

这会按预期返回:List((COOK,List(100, 125, 135, 145),ENG), (KIM,List(115, 134, 148, 154),AUS), (TIM,List(102, 105),ZIM), (VIR,List(115, 120, 134),IND))

_._1 是您访问元组条目的方式。

更新 2:继续排序

这是可能的,但 AFAIK 它变得复杂。我不确定这是否足够可读:

st
  .zipWithIndex // add an index for later sorting
  .groupBy { case (e, _) => (e._1, e._3) }
  .map { case ((n, c), groupedList) => (n,
    groupedList.map { case (trible, index) => (trible._2, index) } // you are only interested in the list and the index
      .foldLeft((List.empty[String], Int.MaxValue)) { case ((list1, i1), (list2, i2)) =>
        (list1 ++ list2, Math.min(i1, i2)) // fold over all the lists and take the minimal index
      }
    , c)
  }.toList
  .sortBy { case (_, (_, index), _) => index } // sort the result by the index
  .map { case (n, (list, _), c) => (n, list, c) } // get rid of the index

【讨论】:

  • 当列表中包含2个以上的元素时怎么办
  • List(("VIR",List("115"),"IND"),("KIM",List("115"),"AUS"),("COOK",List ("100"),"ENG"),("VIR",List("120","134"),"IND"),("KIM",List("134","148","154" ),"AUS"),("COOK",List("125","135","145"),"ENG"),("TIM",List("102","105"),"ZIM ")) 并且我想基于第一个和第三个合并第二个元组,并且列表的顺序也不应该打破就像上面的列表最终列表一样: List(("VIR",List("115","120"," 134"),"IND"),("KIM",List("115","134","148","154"),"AUS"),("COOK",List("100"," 125","135","145"),"ENG"),("TIM",List("102","105"),"ZIM"))
  • 谢谢!!通过这种方法的另一件事我得到了根据第一个元素的字母顺序的最终列表,但我希望顺序与之前的列表相同,例如我的列表是 :::List(("VIR",List("115") ,"IND"),("KIM",List("115"),"AUS"),("COOK",List("100"),"ENG"),("VIR",List("120" ,"134"),"IND"),("KIM",List("134","148","154"),"AUS"),("COOK",List("125","135" ,"145"),"ENG"))
  • 最后列表应该是 :::List(("VIR",List("115","120","134"),"IND"),("KIM",List( "115","134","148","154"),"AUS"),("COOK",List("100","125","135","145"),"ENG") ,("TIM",List("102","105"),"ZIM"))
  • 即列表应该以“VIR”开头这并不意味着顺序应该颠倒我想要像原始列表一样的顺序意味着如果它以VIR开头结束列表也应该以VIR开头然后然后合并
猜你喜欢
  • 2018-11-11
  • 1970-01-01
  • 2018-11-27
  • 2022-12-07
  • 2021-06-15
  • 2019-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多