【问题标题】:Merging List of Tuple List in scalascala中元组列表的合并列表
【发布时间】:2016-10-08 04:09:44
【问题描述】:

我有一个包含重叠元素的元组列表。

val tupLis:Seq[(List[(Integer,Char)],Int)] = null//data

我正在尝试合并元组列表中的重叠元素。这是我正在处理的代码,它使用 foldleft 来合并列表中的重叠元组列表。合并无法正常工作,因为它错过了元组列表的一些元素。每个元组列表中包含 4 个元组.列表中的每个元组列表经常重叠,因为它们是使用滑动函数从更大的列表生成的。

val alLis:Seq[(List[(Integer,Char)],Int)] = snGrMap.map(_._2).flatten.toList.sortBy(_._1.head._1)
val res = alLis.foldLeft(mutable.HashMap.empty[Int,(List[Integer],List[(Integer,Char)],Int)]) { (map, value) =>
  if(map.size<=0){
    map.put(0,(value._1.map(_._1),value._1,value._2))
  }else{
    val cads = map.filter(p=>value._1.intersect(p._2._2).size>=3)
    if(cads.size>=1) {
      cads.foreach { i =>
        val cmnPos = i._2._1.intersect(value._1.map(_._1))
        val cmnBase = i._2._2.filter(p=>cmnPos.contains(p._1)).intersect(value._1.filter(p=>cmnPos.contains(p._1)))
        println(cmnBase.size,cmnPos.size,value._1, i._2._2)
        if(cmnBase.size == cmnPos.size)
          map.put(i._1,((i._2._1++value._1.map(_._1)).distinct,(i._2._2++value._1).distinct,i._2._3+value._2))
        else
          map.put(map.size,(value._1.map(_._1),value._1,value._2))
      }
    }else{
      map.put(map.size,(value._1.map(_._1),value._1,value._2))
    }
  }
  map
}

这是我正在使用的示例数据:

(List((306,c), (328,g), (336,a), (346,g)),282)
(List((306,g), (328,c), (336,g), (346,a)),22)
(List((306,c), (328,c), (336,g), (346,a)),4)
(List((328,g), (336,a), (346,g), (348,t)),164)
(List((328,g), (336,a), (346,g), (348,c)),161)
(List((328,c), (336,g), (346,a), (348,c)),28)
(List((336,a), (346,g), (348,t), (358,a)),168)
(List((336,a), (346,g), (348,c), (358,a)),154)
(List((336,g), (346,a), (348,c), (358,g)),30)
(List((346,g), (348,t), (358,a), (361,c)),178)
(List((346,g), (348,c), (358,a), (361,c)),166)
(List((346,a), (348,c), (358,g), (361,g)),34)

合并后的列表如下:

List((306,c), (328,g), (336,a), (346,g), (348,t), (358,a), (361,c),792)
List((306,c), (328,g), (336,a), (346,g), (348,c), (358,a), (361,c) ),763)
List((306,g), (328,c), (336,g), (346,a), (348,c),  (358,g), (361,g) ),96)

更新 1:

重叠:如果两个元组列表在两个列表中都存在3个或更多精确元组,那么它们应该是重叠的元组列表。但是当两个列表合并时应该没有任何区别。如果其中一个两个列表中的元组值具有相同的整数但不同的字符,则它们不应合并。 合并:当它们重叠时合并两个或多个元组列表。

更新 2:我想出了一个小解决方案,但不确定它的效率如何。

val alLisWithIndex = alLis.zipWithIndex
    val interGrps = new ListBuffer[(Int,Int)]()
    alLisWithIndex.foreach{i=>
      val cads = alLisWithIndex.filter(p=>p._1._1.take(3).intersect(i._1._1.takeRight(3)).size>=3)
      cads.foreach(p=>interGrps.append((i._2,p._2)))
    }
println(interGrps.sortBy(_._1))

所以当我打印上面的代码时,我得到了以这种方式分组的元组列表。我只打印了应该合并的每个元组组的索引。

生成的结果:ListBuffer((0,2), (0,3), (1,4), (2,5), (3,6), (4,7), (5,8), (6,9), (7,10))

这里是元组列表及其使用的索引

List(((List((306,c), (328,g), (336,a), (346,g)),282),0),
((List((306,g), (328,c), (336,g), (346,a)),22),1),
((List((328,g), (336,a), (346,g), (348,t)),164),2),
((List((328,g), (336,a), (346,g), (348,c)),161),3),
((List((328,c), (336,g), (346,a), (348,c)),28),4),
((List((336,a), (346,g), (348,t), (358,a)),168),5),
((List((336,a), (346,g), (348,c), (358,a)),154),6),
((List((336,g), (346,a), (348,c), (358,g)),30),7),
((List((346,g), (348,t), (358,a), (361,c)),178),8),
((List((346,g), (348,c), (358,a), (361,c)),166),9),
((List((346,a), (348,c), (358,g), (361,g)),34),10))

所以现在我要做的就是使用interGrps,根据第二个值链接组,最后用元组列表替换索引..

【问题讨论】:

  • 合并列表的定义(以及“重叠”的含义)非常不清楚,尤其是在您没有给出总数的情况下。
  • 抱歉,还不清楚。当具有相同整数值的 char 存在差异时,它们是否“重叠”?这有点令人困惑,因为您在那里使用“合并”。说“如果两个列表共享 3 个或更多元组,并且任何一对具有相同编号的元组没有不同的字符,那么它们是否重叠?”
  • 是的,如果两个列表共享3个或更多元组,则两个列表重叠,并且任何一对相同编号的元组没有不同的字符"
  • 但这会产生更多的输出元素,而不是更少,因为现在重叠的东西更少了。查看我更新的问题 - 仍然无法给出正确答案
  • 我已经用我最终得到的答案更新了问题。

标签: list scala merge overlapping foldleft


【解决方案1】:

我认为,下面的代码是对您的算法的描述。但是,它并没有给出相同的输出,所以还有一些东西需要弄清楚你想要什么

一、测试数据

var xs = List(
(List((306,"c"), (328,"g"), (336,"a"), (346,"g")),282),
(List((306,"g"), (328,"c"), (336,"g"), (346,"a")),22),
(List((306,"c"), (328,"c"), (336,"g"), (346,"a")),4),
(List((328,"g"), (336,"a"), (346,"g"), (348,"t")),164),
(List((328,"g"), (336,"a"), (346,"g"), (348,"c")),161),
(List((328,"c"), (336,"g"), (346,"a"), (348,"c")),28),
(List((336,"a"), (346,"g"), (348,"t"), (358,"a")),168),
(List((336,"a"), (346,"g"), (348,"c"), (358,"a")),154),
(List((336,"g"), (346,"a"), (348,"c"), (358,"g")),30),
(List((346,"g"), (348,"t"), (358,"a"), (361,"c")),178),
(List((346,"g"), (348,"c"), (358,"a"), (361,"c")),166),
(List((346,"a"), (348,"c"), (358,"g"), (361,"g")),34))

现在有一种方法来实现“如果两个元组列表在两个列表中都有 3 个或更多精确的元组,那么它们应该是重叠的元组列表。”

def isOverlap[A](a:(List[A],Int),b:(List[A],Int)) = (a._1 intersect b._1).size >= 3

然后,使用我在here 上写的东西,根据谓词对“匹配”的元素进行分组

def groupWith[A](xs: List[A], f: (A, A) => Boolean) = {
  // helper function to add "e" to any list with a member that matches the predicate
  // otherwise add it to a list of its own
  def addtoGroup(gs: List[List[A]], e: A): List[List[A]] = {
    val (before, after) = gs.span(_.exists(!f(_, e)))
    if (after.isEmpty)
      List(e) :: gs
    else
      before ::: (e :: after.head) :: after.tail
  }
  // now a simple foldLeft adding each element to the appropriate list
  xs.foldLeft(Nil: List[List[A]])(addtoGroup)
}  

我们可以得到重叠元素的列表

List(List((List((346,g), (348,c), (358,a), (361,c)),166), 
          (List((346,g), (348,t), (358,a), (361,c)),178)),
     List((List((346,a), (348,c), (358,g), (361,g)),34),
          (List((336,g), (346,a), (348,c), (358,g)),30)), 
     List((List((336,a), (346,g), (348,c), (358,a)),154),
          (List((336,a), (346,g), (348,t), (358,a)),168)), 
     List((List((328,c), (336,g), (346,a), (348,c)),28),
          (List((306,c), (328,c), (336,g), (346,a)),4),
          (List((306,g), (328,c), (336,g), (346,a)),22)),
     List((List((328,g), (336,a), (346,g), (348,c)),161),
          (List((328,g), (336,a), (346,g), (348,t)),164),
          (List((306,c), (328,g), (336,a), (346,g)),282)))

然后我们编写一个函数来合并重叠元组的列表:

def merge(ys: List[(List[(Int, String)], Int)]) = 
   ys.foldLeft((Nil:List[(Int, String)], 0))
  {(acc, e) => ((acc._1 ++ (e._1 diff acc._1)).sorted, acc._2 + e._2)}

(通过添加任何尚未在累积结果中的元组来合并元组,然后将整数相加。.sorted 只是为了更容易直观地查看结果)

然后合并重叠的条目

ms.map(merge)

给出这个,但这不是你的输出?

List((List((346,g), (348,c), (348, t), (358,a), (361,c)),344), 
     (List((336,g), (346,a), (348,c), (358,g), (361, g)),64),
     (List((336,a), (346,g), (348,c), (348,t), (358,a)),322),
     (List((306,c), (306,g), (328,c), (336,g), (346,a), (348,c)),54),
     (List((306,c), (328,g), (336,a), (346,g), (348,c), (348,t)),607))

编辑:在 cmets 之后,这里是更新的 isOverlap。但是,这意味着比原始的重叠更少,因此最终合并输出中的元素更多,因此仍然不对:

def isOverlap(a:(List[(Int, String)],Int),b:(List[(Int, String)],Int)) =
  // combine the tuples by Int, and check that we don't get two entries
  // for any Int (i.e. if we do, they have different Strings so it's not an overlap)
 !((a._1++b._1).groupBy(_._2).exists(_._2.length > 1)) &&
  // check there are at least 2 matching tuples
  (a._1 intersect b._1).size >= 3  

【讨论】:

  • 感谢您的回复。我看到了问题。对不起,我错过了解释中的一个条件。当我合并元组列表时,它们应该至少有 3 个重叠,但没有区别。(即)在您的输出中,元组的第一个列表有 '(348,c), (348,t)'。我将更新问题,
  • 没关系,谢谢。当两个元组合并时,它们是两个条件- 1.根据描述,它们应该有3个以上的交集。 2.如果两个列表中的任何元组具有相同的整数但不同的字符串/字符作为其值,则它们不能组合在一起。
  • 哦,很酷,所以只需更改 isOverlap 即可。但是,这将提供更多重叠的组,因此最终合并列表会更长。但是我的代码已经生成了一个比你在问题中的输出更长的列表,所以这似乎不对。
  • 我不确定,因为当我使用我提到的条件进行测试时,我总是得到比应有的更少的序列。所以我想出了不同的解决方案,但没有让它变得如此复杂。我刚刚把它贴在上面。不知道它的效率如何。
  • 查看我对您问题的评论。
猜你喜欢
  • 2021-12-13
  • 2014-06-23
  • 1970-01-01
  • 2016-08-15
  • 2016-11-15
  • 2023-03-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多