我正在研究一个小型数据分析工具,并在此过程中练习/学习Scala。但是我遇到了一个小问题。
假设数据类型为:
X Gr1 x_11 ... x_1n
X Gr2 x_21 ... x_2n
..
X GrK x_k1 ... x_kn
Y Gr1 y_11 ... y_1n
Y Gr3 y_31 ... y_3n
..
Y Gr(K-1) ...
这里我有条目(X,Y ......),在最多K组中可能存在或不存在,每组有一系列值。我想要做的是非常简单(理论上),我想在不同的组中合并属于同一“实体”的行。因此,我希望在列中包含从X
到x_11
的所有值的一行,而不是以x_kn
开头的多行。
X x_11 x_12 x_21 x_22 x_31 x_32
Y y_11 y_12 N/A N/A y_31 y_32
Z N/A N/A z_21 z_22 N/A N/A
我一直试图解决这个问题,有没有一种聪明的方法来使用List函数来解决这个问题?
我写了这个简单的循环:
for {
(id, hitlist) <- hits.groupBy(_.acc)
h <- hitlist
} println(id + "\t" + h.sampleId + "\t" + h.ratios.mkString("\t"))
能够生成看起来像上面示例的表。请注意,我的原始数据具有不同的格式和布局,但这与手头的问题几乎没有关系,因此我跳过了有关解析的所有步骤。我应该能够以更好的方式使用groupBy
来实际解决这个问题,但我似乎无法实现这一目标。
然后我修改了我的循环,将hits
映射到ratios
并将它们相互追加:
for ((id, hitlist) <- hits.groupBy(_.acc)){
val l = hitlist.map(_.ratios).foldRight(List[Double]()){
(l1: List[Double], l2: List[Double]) => l1 ::: l2
}
println(id + "\t" + l.mkString("\t"))
//println(id + "\t" + h.sampleId + "\t" + h.ratios.mkString("\t"))
}
这让我更近了一步,但仍然没有雪茄!而不是一个完全填充的“矩阵”,我得到一个锯齿状的表。以上面的例子为例:
X x_11 x_12 x_21 x_22 x_31 x_32
Y y_11 y_12 y_31 y_32
Z z_21 z_22
关于如何填充表格以使各个组的值彼此对齐的任何想法?我应该可以使用_.sampleId
,它为每个“点击”保留“组成员”,但我不确定如何。 'hit'是一个类型Hit
的列表,实际上是每行的包装器,为获取单个值提供了方便的方法,因此基本上是一个具有“命名索引”的元组(例如.acc
,{ {1}} ..)
(我想解决这个问题而不用硬编码组的数量,因为它可能会因情况而异)
谢谢!
答案 0 :(得分:2)
这是一个人为的例子,但我认为你可以看到它的发展方向:
case class Hit(acc:String, subAcc:String, value:Int)
val hits = List(Hit("X", "x_11", 1), Hit("X", "x_21", 2), Hit("X", "x_31", 3))
val kMax = 4
val nMax = 2
for {
(id, hitlist) <- hits.groupBy(_.acc)
k <- 1 to kMax
n <- 1 to nMax
} yield {
val subId = "x_%s%s".format(k, n)
val row = hitlist.find(h => h.subAcc == subId).getOrElse(Hit(id, subId, 0))
println(row)
}
//Prints
Hit(X,x_11,1)
Hit(X,x_12,0)
Hit(X,x_21,2)
Hit(X,x_22,0)
Hit(X,x_31,3)
Hit(X,x_32,0)
Hit(X,x_41,0)
Hit(X,x_42,0)
如果您提供有关hits
列表的更多信息,那么我们可能会提供一些更准确的信息。
答案 1 :(得分:0)
我已经设法使用以下代码解决了这个问题,我将其作为答案,以防其他人遇到类似问题并需要一些帮助。使用诺亚答案的find()
肯定非常有用,所以如果这段代码片段可以帮助你,请给他一个+1。
val samples = hits.groupBy(_.sampleId).keys.toList.sorted
for ((id, hitlist) <- hits.groupBy(_.acc)) {
val ratios =
for (sample <- samples)
yield hitlist.find(h => h.sampleId == sample).map(_.ratios)
.getOrElse(List(Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN))
println(id + "\t" + ratios.flatten.mkString("\t"))
}
我认为这不是一个非常优雅或有效的解决方案,因为我有两次调用groupBy
,我有兴趣看到更好的解决方案来解决这个问题。