当前位置: 首页 > 知识库问答 >
问题:

Java Stream:有没有一种方法可以迭代,每次使用两个元素而不是一个?

杨昊
2023-03-14
Stream.of("a", "b", "err1", "c", "d", "err2", "e", "f", "g", "h", "err3", "i", "j");
Map<String, String> map = new HashMap<>();

Stream.of("a", "b", "err1", "c", "d", "err2", "e", "f", "g", "h", "err3", "i", "j")
.reduce((acc, next) -> {
    if (acc.startsWith("err"))
        map.put(acc,next);
    if (next.startsWith("err"))
        return next;
    else
        return "";
});

但我对它并不完全满意,主要有两个原因

  1. 我“滥用”了reduce函数。在Stream API中,每个函数都有其明确、明确的用途:max被认为是计算最大值,filter被认为是根据条件进行筛选,reduce被认为是生成增量累加的值,等等。
  2. 这样做会阻止我使用Streams强大的机制:如果我想将搜索限制在前两个结果上怎么办?

这里我使用了reduce,因为(据我所知)它是唯一一个允许比较两个值的函数,而这些值可以在某种程度上导致类似于“当前值”和“下一个值”的概念。

有没有更直截了当的办法?允许您在每次迭代时考虑多个值来迭代流的东西?

我所考虑的是一些机制,在给定当前元素的情况下,允许您为每次迭代定义一个“元素窗口”来考虑。

类似于

<R> Stream<R> mapMoreThanOne(
    int elementsBeforeCurrent,
    int elementsAfterCurrent,
    Function<List<? super T>, ? extends R> mapper);

而不是

<R> Stream<R> map(Function<? super T, ? extends R> mapper);

这将是对当前API的强大“升级”。

我感谢人们提出解决方案的努力,但问题不在于算法本身。有不同的方法来实现我的目标,把流,索引,临时变量存储以前的值...但我想知道在Stream API中是否有一些方法是为处理当前元素以外的元素而设计的,而不破坏“Stream范式”。像这样的东西

List<String> list =
        Stream.of("a", "b", "err1", "c", "d", "err2", "e", "f", "g", "h", "err3", "i", "j")
        .filterFunctionImWonderingIfExist(/*filters couples of elements*/)
        .limit(2)
        .collect(Collectors.toList());

在给出这些答案之后,我认为没有“清晰而快速”的解决方案,除非使用StreamEx库

共有1个答案

宰父学
2023-03-14

可以为此任务生成自定义收集器

Map<String, String> map = 
    Stream.of("a", "b", "err1", "c", "d", "err2", "e", "f", "g", "h", "err3", "i", "j")
          .collect(MappingErrors.collector());

与:

private static final class MappingErrors {

    private Map<String, String> map = new HashMap<>();

    private String first, second;

    public void accept(String str) {
        first = second;
        second = str;
        if (first != null && first.startsWith("err")) {
            map.put(first, second);
        }
    }

    public MappingErrors combine(MappingErrors other) {
        throw new UnsupportedOperationException("Parallel Stream not supported");
    }

    public Map<String, String> finish() {
        return map;
    }

    public static Collector<String, ?, Map<String, String>> collector() {
        return Collector.of(MappingErrors::new, MappingErrors::accept, MappingErrors::combine, MappingErrors::finish);
    }

}

在这个收集器中,保留了两个正在运行的元素。每次接受字符串时,都会更新它们,如果第一个字符串以“err”开头,则将这两个元素添加到映射中。

Map<String, String> map = 
    StreamEx.of("a", "b", "err1", "c", "d", "err2", "e", "f", "g", "h", "err3", "i", "j")
            .pairMap((s1, s2) -> s1.startsWith("err") ? new String[] { s1, s2 } : null)
            .nonNull()
            .toMap(a -> a[0], a -> a[1]);

System.out.println(map);
 类似资料:
  • 问题内容: 假设我们有这个流 我想在地图中保存几对相邻的字符串,其中第一个以“ err”开头。 我想到的就是这样 但是我对它并不完全满意,主要有两个原因 我在“滥用” 功能。在Stream API中,每个函数都有其明确的定义明确的目的:应该计算最大值,应该根据条件进行过滤,应该产生递增的累加值,依此类推。 这样做会使我无法使用Streams强大的机制:如果我想将搜索范围限制在前两个结果中,该怎么办

  • 问题内容: 我有一个在HashMap上使用的迭代器,并且保存并加载了该迭代器。有没有办法用迭代器在HashMap中获取上一个密钥?(java.util.Iterator) 更新资料 我将其另存为Red5连接中的属性,然后将其重新加载以在我停止的地方继续工作。 另一个更新 我正在遍历HashMap的键集 问题答案: 正如其他人指出的那样,它并不直接,但是例如,如果您需要访问一个先前的元素,则可以轻松

  • Go的范围可以在地图和切片上迭代,但我想知道是否有一种方法可以在一系列数字上迭代,比如: 或者有没有一种方法来表示Go中的整数范围,就像Ruby对类范围所做的那样?

  • 例如,-从索引0迭代到索引10。 -但从10到0不起作用,如何使用流API实现?

  • 问题内容: 我一直在寻找一种操作类似于的方法,但忽略了元素顺序。我在Google Collections(类似,但确实能说明订购)和JUnit(显然只是调用Collection,这取决于Collection的实现,而这并不是我想要的)中都找不到。如果此方法采用s 是最好的,但是我也可以简单地采用s。这样的方法当然会考虑集合中的所有重复元素(因此不能简单地测试)。 请注意,我并不是在问如何实现这样的

  • 如何才能做到这一点呢? 谢谢大家。