合并列表[列表[_]]有条件

时间:2018-03-21 15:10:20

标签: scala list functional-programming stream

我想根据内部列表中元素的值合并List[List[Double]]。这是我到目前为止所做的:

// inner Lists are (timestamp, ID, measurement)
val data = List(List(60, 0, 3.4),  List(60, 1, 2.5),  List(120, 0, 1.1),
                List(180, 0, 5.6), List(180, 1, 4.4), List(180, 2, 6.7))

data
  .foldLeft(List[List[Double]]())(
    (ret, ll) =>

      // if this is the first list, just add it to the return val
      if (ret.isEmpty){
        List(ll)

      // if the timestamps match, add a new (ID, measurement) pair to this inner list
      } else if (ret(0)(0) == ll(0)){
        {{ret(0) :+ ll(1)} :+ ll(2)} :: ret.drop(1)

      // if this is a new timestamp, add it to the beginning of the return val
      } else {
        ll :: ret
      }
  )

这很有效,但它对我来说并不是最佳的(特别是正确的加法“:+”)。对于我的用例,我有一个非常大的(~25,000个内部列表)元素列表,它们本身都是长度为3的列表。最多会有四倍的简并性,因为内部列表是List(timestamp, ID, measurement)组,并且只有四个唯一ID。基本上,我想将所有具有相同时间戳的测量结果汇总在一起。

有没有人看到更好的方法呢?

如果从这一点开始有更好的方法,我实际上从四个ID中的每一个开始都有List[Double]个时间戳和List[Double]个测量值。

3 个答案:

答案 0 :(得分:2)

这是一种稍微简短的方法:

data.
  groupBy(_(0)).
  mapValues(_.flatMap(_.tail)).
  toList.
  map(kv => kv._1 :: kv._2)

结果看起来与您的算法产生的结果完全相同:

List(List(180.0, 0.0, 5.6, 1.0, 4.4, 2.0, 6.7), List(120.0, 0.0, 1.1), List(60.0, 0.0, 3.4, 1.0, 2.5))
List(List(180.0, 0.0, 5.6, 1.0, 4.4, 2.0, 6.7), List(120.0, 0.0, 1.1), List(60.0, 0.0, 3.4, 1.0, 2.5))

说明:

  • 按时间戳分组
  • 在分组值中,删除冗余时间戳,并展平为单个列表
  • 将时间戳恢复到ids& -measurements的平面列表

答案 1 :(得分:2)

这是一种可能性:

input
  .groupBy(_(0))
  .map { case (tstp, values) => tstp :: values.flatMap(_.tail) }

这个想法只是按照第一个元素对内部列表进行分组,然后将结果值展平。

返回:

List(List(180.0, 0.0, 5.6, 1.0, 4.4, 2.0, 6.7), List(120.0, 0.0, 1.1), List(60.0, 0.0, 3.4, 1.0, 2.5))

答案 2 :(得分:1)

如何用案例类来表示您的测量结果?

case class Measurement(timestamp: Int, id: Int, value: Double)

val measurementData = List(Measurement(60, 0, 3.4),  Measurement(60, 1, 2.5),  
    Measurement(120, 0, 1.1), Measurement(180, 0, 5.6), 
    Measurement(180, 1, 4.4), Measurement(180, 2, 6.7))

measurementData.foldLeft(List[Measurement]())({
    case (Nil, m) => List(m)
    case (x :: xs, m) if x.timestamp == m.timestamp => m :: xs
    case (xs, m) => m :: xs
  })