2017-04-26 90 views
2

我正在嘗試線性插入Array[Option[Long]]。例如,給定:在Scala中插入數組

val example1 = Array(Some(20l), None, Some(60l)) 
val example2 = Array(Some(20l), None, None, Some(80l)) 
val example3 = Array(Some(20l), None, None, Some(80l), Some(90l), Some(100l)) 
val example4 = Array(Some(20l), None, None, Some(80l), None, Some(82l)) 

我期待:

val example1Interpolated = Array(20l, 40l, 60l) 
val example2Interpolated = Array(20l, 40l, 60l, 80l) 
val example3Interpolated = Array(20l, 40l, 60l, 80l, 90l, 100l) 
val example4Interpolated = Array(20l, 40l, 60l, 80l, 81l, 82l) 

有集合(例如example4)中的元素之間沒有任何關係。但是這些值是單調遞增的。

對於那些熟悉Python我正在尋找斯卡拉相當於如下:

def interpolate(input_): 
    nans = np.isnan(input_) 
    get_index = lambda z: z.nonzero()[0] 
    input_[nans] = np.interp(get_index(nans), get_index(~nans), input_[~nans]) 
    return input_ 

這爲:

interpolate(np.array([20, np.nan, 60])) 
interpolate(np.array([20, np.nan, np.nan, 80])) 
interpolate(np.array([20, np.nan, np.nan, 80, np.nan, 82])) 

產量:

array([ 20., 40., 60.]) 
array([ 20., 40., 60., 80.]) 
array([ 20., 40., 60., 80., 81., 82.]) 
+2

你到目前爲止嘗試過什麼?你在哪裏被封鎖?你有什麼具體問題? – sjrd

+0

@sjrd理想情況下尋找一種功能性的方式來做到這一點給予任何集合的可選值。想知道是否有某個軟件包中的某個實現可以讓某人知道或我缺少的其他東西。 –

+3

@AmirZiai您應該在您的問題中添加所需的確切要求。 –

回答

3

此功能將工作,即使有前導或尾隨None,只要有其中的Some(_)列表中至少一個元素。它也是通用的Integral類型。 (你可以把它整個Fractional類型的通用,如果你想。)

def interpolate[T](list: Iterable[Option[T]])(implicit num: Integral[T]) = { 
    import num._ 
    val prevs = list.zipWithIndex.scanLeft(Option.empty[(T, Int)]) { 
    case (prev, (cur, i)) => cur.map((_, i)).orElse(prev) 
    } 
    val nexts = list.zipWithIndex.scanRight(Option.empty[(T, Int)]) { 
    case ((cur, i), next) => cur.map((_, i)).orElse(next) 
    } 
    prevs.tail.zip(nexts).zipWithIndex.map { 
    case ((Some((prev, i)), Some((next, j))), k) => 
     if (i == j) prev else prev + (next - prev) * fromInt(k - i)/fromInt(j - i) 
    case ((Some((prev, _)), _), _) => prev 
    case ((_, Some((next, _))), _) => next 
    } 
} 

這建立了prevs,這使最近Some(_)其索引到左側,nexts的軌道,這是相同的對。然後,並行迭代prevsnexts,它會根據左側,右側和索引生成插值。如果左側或右側缺失,請從另一側填寫。

2

我不是熟悉numpy,但我認爲這可以處理你所有的案例。它假定列表中的第一個和最後一個元素將被定義(如果不是這種情況,您將不得不重新使用fillNones函數)。

def interpolate(list: List[Option[Long]]) = { 

    // Creates a new list that will be used to replace a sequence of Nones 
    def fillNones(noneCount: Int, min: Long, max: Long): List[Long] = { 
    val stepSize = (max - min)/(noneCount + 1) 
    (1 to noneCount).toList.map(i => i * stepSize + min) 
    } 

    // We will recursively traverse the list 
    def recursive(done: List[Long], todo: List[Option[Long]]): List[Long] = { 
    todo match { 

     // If todo is empty, we are done 
     case Nil => done 

     // If the head of todo is Some(Long), then add it to the list of things that are done and move on 
     case Some(l) :: tail => recursive(done :+ l, tail) 

     // If the head wasn't Some(Long), then we have to figure out how many Nones are in a row, and replace them 
     case todo => 

     // Find out how many Nones are in a row 
     val noneCount = todo.takeWhile(_.isEmpty).length 

     // Split the todo so we can get what is remaining 
     val remaining = todo.splitAt(noneCount)._2 

     // Create a new list to replace the sequence of Nones 
     val filled = fillNones(noneCount, done.last, remaining.head.get) 

     // Add our new filled list to done, and continue on 
     recursive(done ++ filled, remaining) 
    } 
    } 

    recursive(List.empty, list) 
} 

測試:

val example1 = List(Some(20l), None, Some(60l)) 
println(interpolate(example1)) 
// Prints: List(20, 40, 60)  

val example2 = List(Some(20l), None, None, Some(80l)) 
println(interpolate(example2)) 
// Prints: List(20, 40, 60, 80) 

val example3 = List(Some(20l), None, None, Some(80l), Some(90l), Some(100l)) 
println(interpolate(example3)) 
// Prints: List(20, 40, 60, 80, 90, 100) 

val example4 = List(Some(20l), None, None, Some(80l), None, Some(82l)) 
println(interpolate(example4)) 
// Prints: List(20, 40, 60, 80, 81, 82)