복붙노트

[SCALA] 불평등 길이리스트의 목록을 전치하는 스칼라에서 안전한 방법이 있습니까?

SCALA

불평등 길이리스트의 목록을 전치하는 스칼라에서 안전한 방법이 있습니까?

다음 목록을 감안할 때 :

val l = List(List(1, 2, 3), List(4, 5), List(6, 7, 8))

나는 그것을 전치하려고하면, 스칼라는 다음과 같은 오류가 발생합니다 :

scala> List.transpose(l)
java.util.NoSuchElementException: head of empty list
    at scala.Nil$.head(List.scala:1365)
    at scala.Nil$.head(List.scala:1362)
    at scala.List$$anonfun$transpose$1.apply(List.scala:417)
    at scala.List$$anonfun$transpose$1.apply(List.scala:417)
    at scala.List.map(List.scala:812)
    at scala.List$.transpose(List.scala:417)
    at .<init>(<console>:6)
    at .<clinit>(<console>)
    at RequestResult...

List.transpose가 동일한 길이의 목록을 가정하고 있으므로 헤드 방식을 사용하기 때문입니다 :

def transpose[A](xss: List[List[A]]): List[List[A]] = {
  val buf = new ListBuffer[List[A]]
  var yss = xss
  while (!yss.head.isEmpty) {
    buf += (yss map (_.head))
    yss = (yss map (_.tail))
  }
  buf.toList
}

나는 다음을 좀하고 싶습니다 :

List(List(1, 4, 6), List(2, 5, 7), List(3, 8))

전치 내 자신의 버전이 작업을 수행하는 가장 좋은 방법을 쓰고있다? 이것은 내가 생각 해낸 것입니다 :

def myTranspose[A](xss: List[List[A]]): List[List[A]] = {
  val buf = new ListBuffer[List[A]]
  var yss = xss
  while (!yss.head.isEmpty) {
    buf += (yss filter (!_.isEmpty) map (_.head))
    yss = (yss filter (!_.isEmpty) map (_.tail))
  }
  buf.toList
}

업데이트 : 내가 함께 다음과 같은 작은 벤치 마크를 넣어, 그래서 내가 여기에 제공되는 다른 솔루션의 속도를 비교에 관심이되었다 :

import scala.testing.Benchmark
import scala.collection.mutable.ListBuffer

trait Transpose extends Benchmark {
  def transpose[Int](xss: List[List[Int]]): List[List[Int]] = Nil
  val list: List[List[Int]] = List(List(1,2,3), Nil, List(4,5,99,100), List(6,7,8))
  def run = {
    val l = transpose(list)
    println(l)
    l
  }
}

object PRTranspose extends Transpose {
  override def transpose[Int](xss: List[List[Int]]): List[List[Int]] = {
    val buf = new ListBuffer[List[Int]]
    var yss = xss
    while (!yss.head.isEmpty) {
      buf += (yss filter (!_.isEmpty) map (_.head))
      yss = (yss filter (!_.isEmpty) map (_.tail))
    }
    buf.toList
  }
}

object ACTranspose extends Transpose {
  override def transpose[Int](xss: List[List[Int]]): List[List[Int]] = {
    val b = new ListBuffer[List[Int]]
    var y = xss filter (!_.isEmpty)
    while (!y.isEmpty) {
      b += y map (_.head)
      y = y map (_.tail) filter (!_.isEmpty)
    }
    b.toList
  }
}

object ETranspose extends Transpose {
  override def transpose[Int](xss: List[List[Int]]): List[List[Int]] = xss.filter(!_.isEmpty) match {    
    case Nil => Nil
    case ys: List[List[Int]] => ys.map{ _.head }::transpose(ys.map{ _.tail })
  }
}

내 명령했다 :

scala PFTranspose 5 out.log
scala ACTranspose 5 out.log
scala ETranspose 5 out.log

내 결과는 :

PRTranspose$            10              0               1               1               0
ACTranspose$            9               2               0               0               0
ETranspose$             9               3               2               3               1

해결법

  1. ==============================

    1.이것은 어떤가요:

    이것은 어떤가요:

        scala> def transpose[A](xs: List[List[A]]): List[List[A]] = xs.filter(_.nonEmpty) match {    
             |     case Nil    =>  Nil
             |     case ys: List[List[A]] => ys.map{ _.head }::transpose(ys.map{ _.tail })
             | }
        warning: there were unchecked warnings; re-run with -unchecked for details
        transpose: [A](xs: List[List[A]])List[List[A]]
    
        scala> val ls = List(List(1, 2, 3), List(4, 5), List(6, 7, 8))
        ls: List[List[Int]] = List(List(1, 2, 3), List(4, 5), List(6, 7, 8))
    
        scala> transpose(ls)
        res0: List[List[Int]] = List(List(1, 4, 6), List(2, 5, 7), List(3, 8))
    
        scala> val xs = List(List(1,2,3), List(4,5,99,100), List(6,7,8))
    xs: List[List[Int]] = List(List(1, 2, 3), List(4, 5, 99, 100), List(6, 7, 8))
    
    scala> transpose(xs)
    res1: List[List[Int]] = List(List(1, 4, 6), List(2, 5, 7), List(3, 99, 8), List(100))
    
  2. ==============================

    2.나는 수학적으로 전치 작업 만 "직사각형 구조"에 잘 정의되어 있기 때문에 트랜스가리스트의 "사각형이 아닌"목록에 정의되지 않은 이유는 생각한다. 전치 동작의 바람직한 특성은 그 전치 (전치 (X)) == X. 이 목록의 사각형이 아닌 목록에있는 트랜스 작업의 당신의 일반화의 경우되지 않습니다.

    나는 수학적으로 전치 작업 만 "직사각형 구조"에 잘 정의되어 있기 때문에 트랜스가리스트의 "사각형이 아닌"목록에 정의되지 않은 이유는 생각한다. 전치 동작의 바람직한 특성은 그 전치 (전치 (X)) == X. 이 목록의 사각형이 아닌 목록에있는 트랜스 작업의 당신의 일반화의 경우되지 않습니다.

    또한, 스칼라에서 임의 컬렉션의-컬렉션 전치에 내 게시물을 살펴보고 사각형이 아닌 컬렉션 --컬렉션을 위해 그 일에 대해 생각합니다. 당신은 혼자가 구현을 떠나, 수학적으로 일치 정의로 끝날 것이다.

    나는 이렇게 특이한 "트랜스"작업이 종종 유용하다는 동의하지만, 나는 또한 그들이 그들의 정확한 정의에 대한 잠재적 인 혼란의 표준 라이브러리에서 사용할 수 안된다고 생각합니다.

  3. ==============================

    3.나는 알지 못한다 (그리고 상상할 수없는 -이 조금 이상한?! [의견 토론 참조]입니다하지 않습니다) 라이브러리 기능을하지만 코드 조금을 연마 할 수 있습니다 :

    나는 알지 못한다 (그리고 상상할 수없는 -이 조금 이상한?! [의견 토론 참조]입니다하지 않습니다) 라이브러리 기능을하지만 코드 조금을 연마 할 수 있습니다 :

    scala> def transpose(x: List[List[Int]]): List[List[Int]] = {
         |   val b = new ListBuffer[List[Int]]
         |   var y = x filter (!_.isEmpty)
         |   while (!y.isEmpty) {
         |     b += y map (_.head)
         |     y = y map (_.tail) filter (!_.isEmpty)
         |   }
         |   b.toList
         | }
    
  4. ==============================

    4.이것은 아마도 가장 깨끗한입니다 :

    이것은 아마도 가장 깨끗한입니다 :

    def transpose[T](l: List[List[T]]): List[List[T]] =
         l.flatMap(_.headOption) match {
             case Nil => Nil
             case head => head :: transpose(l.map(_.drop(1)))
         }
    

    또는 더 효율적으로 수정 된 버전입니다 :

    def transpose[T](l: List[List[T]]): List[List[T]] =
         l.flatMap(_.headOption) match {
             case Nil => Nil
             case head => head :: transpose(l.collect { case _ :: tail => tail })
         }
    
  5. ==============================

    5.어떻게 스칼라의 표준 API를 사용하여이 한 줄에 대해 :

    어떻게 스칼라의 표준 API를 사용하여이 한 줄에 대해 :

    ((l map (_.toArray)) toArray).transpose map (_.toList) toList
    

    이 일을 얻고 N 래퍼리스트의 길이이고 M은 래퍼 목록 내부의 긴리스트의 길이이고, O (N * M)입니다.

  6. from https://stackoverflow.com/questions/1683312/is-there-a-safe-way-in-scala-to-transpose-a-list-of-unequal-length-lists by cc-by-sa and MIT license