Scala: Tính tổng di chuyển của danh sách với một cửa sổ cố định


8

Tôi chưa quen với Scala và tôi muốn tính tổng di chuyển với một cửa sổ cố định cho danh sách.

Ví dụ: Cho các giá trị danh sách (1.0, 2.0, 3.0, 6.0, 7.0, 8.0, 12.0, 9.0, 4.0, 1.0) và giai đoạn 4, hàm sẽ trả về: (1.0, 3.0, 6.0, 12.0, 18.0, 24.0, 33.0, 36.0, 33.0, 26.0)

Nếu list.size <period thì chỉ cần trả lại tổng tích lũy.

Tôi đã thực hiện một số nỗ lực

def mavg(values: List[Double], period: Int): List[Double] = {
  if (values.size <= period) (values.sum ) :: List.fill(period -1)(values.sum ) else {
      val rest: List[Double] = mavg(values.tail, period)
      (rest.head + ((values.head - values(period)))):: rest
  }
}

Tuy nhiên, tôi đã nhận

List(12.0, 18.0, 24.0, 33.0, 36.0, 33.0, 26.0, 26.0, 26.0, 26.0

Điều này không đúng. Tôi không muốn sử dụng Pyspark để có kết quả. Ai đó có thể giúp gì không?

Cảm ơn nhiều.


Hãy slidingthử phương pháp
Seth Tisue

1
Tôi nhận thấy rằng cửa sổ phát triển (phần tử thứ nhất, 2 phần tử thứ nhất, 3 phần tử thứ nhất, v.v.) nhưng nó không co lại (4 phần tử cuối cùng, 3 phần tử cuối cùng, 2 phần tử cuối cùng, v.v.). Đó có phải là cố ý?
jwvh

Câu trả lời:


5
  def mavg(values: Seq[Double], period: Int): Seq[Double] = {
    (Seq.fill(math.min(period - 1, values.length))(0.0) ++ values) // padding zeros
      .sliding(period)                  
      .map(_.sum)
      .toSeq
  }

giải pháp tuyệt vời !!!!!
Raman Mishra

2
lưu ý rằng điều này sẽ trả về List(0.0)khi values = Seq()period > 1
CervEd

@CervEd cảm ơn thông báo của bạn, hãy sửa nó
User9123

@ User9123, có thể có nhiều hơn. Phải tự mình thực hiện một số cú nhào lộn trong câu trả lời của tôi
CervEd

3

Đây là một cách để giải quyết nó.

def mavg(values: List[Double], period: Int): List[Double] =
  values.inits    //shrinking list of inits
        .toList   //result type
        .reverse  //growing list of inits
        .tail     //drop the empty one
        .map(_.takeRight(period).sum) //sum the window

thử nghiệm:

mavg(List(1.0, 2.0, 3.0, 6.0, 7.0, 8.0, 12.0, 9.0, 4.0, 1.0), 4)
//res0: List[Double] = List(1.0, 3.0, 6.0, 12.0, 18.0, 24.0, 33.0, 36.0, 33.0, 26.0)

2

Đây là một cách khác bạn có thể làm điều này:

  val l = List(1.0, 2.0, 3.0, 6.0, 7.0, 8.0, 12.0, 9.0, 4.0, 1.0,5.0,1.0,2.0)
  def mavg(step: Int, list: List[Double], ans: List[Double] = List.empty[Double], splitCount: Int = 0): List[Double] = {
    if (list.length > 1) {
      mavg(step - 1, list.take(step), list.sliding(step, 1).toList.map(_.sum) ::: ans, splitCount + 1)
    } else {
      ans.splitAt(splitCount + 2)._1.sliding(1, 2).toList.flatten ::: ans.drop(splitCount + 2)
    }
  }

  val ans = mavg(4, l)
  println(ans)

1

Một cách tiếp cận khác, tương tự như câu trả lời của @ User9123

Sự khác biệt là nó không tính tổng của tất cả các phần tử trong cửa sổ trượt, thay vào đó nó trừ đi giá trị của đầu cửa sổ cuối cùng từ tổng của nó và thêm giá trị của đầu cửa sổ tiếp theo để mang lại tổng số tiếp theo. Điều này sẽ hiệu quả hơn cho các cửa sổ lớn.

def rollingSum[N](values: Seq[N], period: Int)(
    implicit num: Numeric[N]
): Seq[N] = {
  import num._
  values match {
    case values if period == 1 => values // Can't slide on period 1
    case head :: tail if period < values.size =>
      (Seq.fill(period - 2)(num.zero) ++ (values)) // zero padding
        .sliding(period)
        .foldLeft((num.zero, Seq(head))) { // Use a tuple to store previous head
          case ((prevHead, acc), y) => {
            (y.head, acc :+ acc.last - prevHead + y.last) // do the magic
          }
        }
        ._2 // only return the result
    case head :: tail => tail.scanLeft(head)(_ + _) // Regular cummulative sum
    case Nil          => Nil
  }
}

Tôi cũng đã thêm một số vệ sĩ cho các trường hợp đặc biệt cần được xử lý và biến nó thành một chức năng chung cho tất cả các Numericloại.

Đây là một ví dụ đang chạy với một số trường hợp thử nghiệm.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.