【问题标题】:Interpolate Values in Java Stream在 Java 流中插入值
【发布时间】:2017-04-18 09:40:18
【问题描述】:

我有一个包含大约 200,000 个刻度值(日期和值)的列表。该列表不对每个日期都有一个刻度值。但这是我在输出中需要的。所以我需要一些东西来在间隙中添加缺失的刻度值。

我正在使用 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.
    }

}

是否可以向流中添加值,或者我可以获得不包含间隙的结果流?我可以对流进行前瞻(以检测间隙)吗?

【问题讨论】:

  • 据我了解,您不想将元​​素添加到流中(因为您不能,流中不包含任何数据),而是添加到您的列表中,是的,这绝对是可能,只需添加 1 天并检查该日期是否在列表中。
  • 前一天的值为“7”。好的,我换个说法:我能得到一个不包含间隙的结果流吗?

标签: java java-stream


【解决方案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);

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
]

如有不妥,欢迎指正。

【讨论】:

  • 好的,但在“现实生活”中,我没有开始的清单。我只有一个传入流,并且希望避免创建包含所有元素的列表。
  • 我添加了一个使用流的示例。
  • 基于流的实现是否总是适用于并行流?
  • 基于数组的实现可能会起作用,但基于流的实现不会,因为它需要之前的值才能起作用。
猜你喜欢
  • 2016-12-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多