2017-04-18 12 views
1

私は約200,000のティック値(日付と値)を持つリストを持っています。リストはではありません。にはすべての日付のティック値があります。しかし、これは私の出力に必要なものです。だから私はギャップに欠けているティック値を加える何かが必要です。Javaストリームの補間値

私は、Javaストリーム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

ストリームから要素を追加したくないから(ストリームにデータが含まれていないため)、リストに追加する必要はありません。確かに可能ですその日が常にリストにあるかどうかを確認してください。 – Shadov

+0

前日の値は「7」になります。 私は言い換えることができます:ギャップを含まない結果のストリームを得ることはできますか? – David

答えて

2

ギャップがあるかどうかは、以前の値をトラッキングすることで確認できます。これを行う1つの方法は、エントリのインデックスに基づいて直接リストにアクセスすることです。次の解決策は、入力を日付でソートすることを想定しています。

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); 

flatMapmapToObject/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