2017-04-18 61 views
1

我有一個包含約200,000個刻度值(日期和值)的列表。列表確實是而不是對於每個日期都有一個刻度值。但這是我在輸出中需要的。所以我需要在缺口中添加缺少的刻度值。在Java流中內插值

我正在使用Java Stream API處理列表。

class Tick { 
    public LocalDate date; 
    public BigDecimal value; 

    public Tick(LocalDate date, BigDecimal value) { 
     this.date = date; 
     this.value = value; 
    } 
} 

public class DateInterpolator { 

    public static void main(String [] args) 
    { 
     final ArrayList<Tick> list = new ArrayList<>(); 
     list.add(new Tick(LocalDate.of(2017, 1, 1), BigDecimal.valueOf(7))); 
     list.add(new Tick(LocalDate.of(2017, 1, 3), BigDecimal.valueOf(8))); 

     final Stream<Tick> stream = list.stream(); 

     // TODO no value for 2017-01-02 given. 
     // I want to use the value from the day before (7). 
     // Add black magic here. 
    } 

} 

是否可以向流中添加值或者是否可以得到不包含間隙的結果流?我可以根據流來預測(檢測差距)嗎?

+0

根據我的理解,你不想添加元素流(因爲你不能,流不包含任何數據),但對你的列表,是的,這是絕對有可能的,只需加1並一直檢查該日期是否在列表中。 – Shadov

+0

前一天的價值將是「7」。 好的,讓我換句話說:我可以得到一個沒有差距的結果流嗎? – David

回答

2

您可以通過跟蹤以前的值來檢查是否有間隙。一種方法是直接根據條目的索引訪問列表。以下解決方案預計輸入按日期排序。

final Stream<Tick> stream = IntStream.range(0, list.size()) 
    .mapToObj((i) -> { 
    // 'sub' should contain one item. If there are gaps, 
    // sub will contain gap values as well, up to and including the current Tick. 
    final ArrayList<Tick> sub = new ArrayList<>(); 

    Tick curr = list.get(i); 

    if(i > 0) { 
     Tick prev = list.get(i-1); 

     // Fill the gaps if there are any 
     for (LocalDate date = prev.date.plusDays(1); date.isBefore(curr.date); date = date.plusDays(1)) { 
     sub.add(new Tick(date, prev.value)); 
     } 
    } 

    sub.add(curr); // add the current value 

    return sub; 
    }) 
    .flatMap(List::stream); 

或者基於流的實現:

private static Stream<Tick> fillGaps(Stream<Tick> ticks) { 

    final Var prev = new Var(); // required to be final, so a wrapper is needed to modify the instance 

    Stream<Tick> result = ticks 
     .map(curr -> { 
      final ArrayList<Tick> sub = new ArrayList<>(); 

      if(prev.instance != null) { 
       for (LocalDate date = prev.instance.date.plusDays(1); date.isBefore(curr.date); date = date.plusDays(1)) { 
        sub.add(new Tick(date, prev.instance.value)); 
       } 
      } 

      sub.add(curr); 
      prev.instance = curr; 

      return sub; 
     }) 
     .flatMap(l -> l.stream()); 

    return result; 
} 

// Helper class 
class Var { 
    public Tick instance; 
} 

// Usage: 
final Stream<Tick> ticks = fillGaps(stream); 

flatMap變平的中間結果(由mapToObject/map創建):

[ 
    Tick(2017-1-1, 7) // Last item is always an item in the original list 
], 
[ 
    Tick(2017-1-2, 7), // Interpolated value based on the previous value 
    Tick(2017-1-3, 8) // Last item is always an item in the original list 
] 

隨時糾正我的情況下,什麼是錯的。

+0

好吧,但在「現實生活中」,我沒有一個名單開始。我只有一個傳入流,並希望避免創建一個包含所有元素的列表。 – David

+0

我已經添加了一個使用流的示例。 – Caramiriel

+0

基於流的實現總是適用於並行流嗎? – gr7