【问题标题】:Checking range of List in forEach lambda loop Java 8检查 forEach lambda 循环 Java 8 中的列表范围
【发布时间】:2014-09-03 19:58:46
【问题描述】:

我想学习如何在 java 8 中检查列表的范围。

例如,

我的代码:

    List<String> objList = new ArrayList<>();
    objList.add("Peter");
    objList.add("James");
    objList.add("Bart");

    objList.stream().map((s) -> s + ",").forEach(System.out::print);

我的结局是

    Peter,James,Bart,

但我想知道如何摆脱最后一个,

注意:我知道我必须在这里使用过滤器,但我不知道如何,我知道还有另一种方法可以解决这个问题,如下所示

String result = objList.stream()
    .map(Person::getFirstName)
    .collect(Collectors.joining(","));

但我想知道如何在我的第一个代码中检查范围并摆脱 。

【问题讨论】:

  • 为了上帝的爱,当你投反对票时,请说为什么?这个问题有什么问题?
  • ...什么?你有什么困惑吗?
  • no 例如,在命令式风格中,如何检查范围很清楚,但在这里我不知道。我只想去掉最后一个逗号

标签: java foreach lambda java-8


【解决方案1】:

试试这个,

int[] counter = new int[]{0};
objList.stream()
    .map(f -> (counter[0]++ > 0? "," : "") + f)
    .forEach(System.out::print);

【讨论】:

    【解决方案2】:

    我们也可以尝试使用stream API的limit和skip方法来解决这个问题。这是我对这个问题的尝试。

        returnData.stream().limit(returnData.size()-1).forEach(s->System.out.print(s+","));
        returnData.stream().skip(returnData.size()-1).forEach(s->System.out.print(s));
    

    returnData 是具有值 2、4、7、14 的整数列表。输出看起来像 2,4,7,14

    【讨论】:

    • if (returnData.size()&gt;0){ returnData.stream().limit(returnData.size()-1).forEach(s-&gt;System.out.print(s+",")); returnData.stream().skip(returnData.size()-1).forEach(s-&gt;System.out.print(s));}
    【解决方案3】:

    当您自己处理项目时,没有直接的方法来获取流项目的索引。不过,有几种选择。

    一种方法是在索引上运行流,然后从列表中获取元素。对于每个元素索引,它将i 映射到第 i 个元素,并为除最后一个以外的所有索引附加一个“,”:

    IntStream.range(0, objList.size())
        .mapToObj(i -> objList.get(i) + (i < objList.size()-1 ? "," : ""))
        .forEach(System.out::print);
    

    第二种更简洁的变体是对第一个元素而不是最后一个元素进行特殊处理:

    IntStream.range(0, objList.size())
        .mapToObj(i -> (i > 0 ? "," : "") + objList.get(i))
        .forEach(System.out::print);
    

    第三种方法是使用特定的reduce 操作,该操作应用于每个两个相邻元素“之间”。这种技术的问题在于它会进行 O(n^2) 复制,这对于大型流来说会变得非常慢。

    System.out.println(objList.stream().reduce((a,b) -> a + "," + b).get());
    

    第四种方法是通过将流的长度限制为 n-1 来对最后一个元素进行特殊处理。这需要一个单独的 print 语句,但不是很漂亮:

    objList.stream()
        .limit(objList.size()-1)
        .map(s -> s + ",")
        .forEach(System.out::print);
    System.out.print(objList.get(objList.size()-1));
    

    第五种方式与上面类似,特例化第一个元素而不是最后一个:

    System.out.print(objList.get(0));
    objList.stream()
        .skip(1)
        .map(s -> "," + s)
        .forEach(System.out::print);
    

    真的,虽然joining 收集器的目的是为你做这个丑陋和恼人的特殊情况,所以你不必自己做。

    【讨论】:

    • 我接受了你的答案,因为它更接近我正在寻找的内容,但我有一个问题。如何在映射过程中同时访问第一个和第二个元素?
    • @user3674428 如果您正在流式传输列表本身的元素,则不能。如果您有一个列表,您可以使用IntStream.range 创建一个索引流,然后在映射器中使用list.get(i)list.get(i+1)
    • 感谢您的回复。我有一些想法,您可以查看我的另一篇与此相关的帖子并帮助我解决这个问题吗?stackoverflow.com/questions/24770637/filter-twice-lambda-java
    • 它是 k 但谢谢。你的回答让我想到了这个问题,所以我也非常感谢你。 :)
    • 有什么方法可以通过电子邮件与您联系吗?
    【解决方案4】:

    你可以这样做:

    objList.stream().flatMap((s) -> Stream.of(s, ','))
            .limit(objList.size() * 2 - 1).forEach(System.out::print);
    

    flatMap 将原始流中的每个元素替换为映射函数返回的流中的元素。

    所以如果你的流最初是

    "Peter" - "James" - "Bart"
    

    上面的映射函数改成

    "Peter" - "," - "James" - "," - "Bart" - ","
    

    然后limit 删除最后一个"," 通过将流缩短到最多传递给它的值的长度,在这种情况下是流的大小 - 1。 stream 是 limit 之前列表的 2 * 大小,因为 flatMap 是其长度的两倍。

    请注意,如果列表为空,这将抛出 IllegalArgumentException,因为传递给 limit 的值将是 -1。如果可能,您应该先检查一下。

    【讨论】:

    • 你能解释一下flatMap吗?
    • "Peter", ", 你能告诉我逗号加引号和不加引号有什么区别吗?
    • 不带引号是为了分隔元素,它们不在流中。
    • 很有趣,它是如何删除它的?
    • 为什么要多到两个?
    【解决方案5】:
    objList.stream().filter(s -> { return !s.equals("Bart") })
    

    这会将流减少为不等于 Bart 的字符串

    这将打印地图的最后一个值:

    Map<Integer, String> map = new HashMap<>();
    map.put(0, "a");
    map.put(1, "c");
    map.put(2, "d");
    
    Integer lastIndex = map.keySet().size() - 1;
    
    Stream<String> lastValueStream = map.values().stream().filter(s -> s.equals(map.get(lastIndex)));
    

    【讨论】:

    • 你怎么知道 Bart 是最后一项?我想要一般的东西
    • 如果你想使用精确的位置,你将不得不使用 Map - 例如,键是数字,值是你的字符串。具有最高值的键将产生您的最后一个地图值。
    • 能否请您在答案中通过您的代码,以便我可以运行它?
    • 我相当肯定我的小例子会按原样工作....但是既然你问得很好,我实际上会在我的工作场所使用我的开发环境来测试它......一会儿请。
    • 不是答案部分的代码。我在评论部分谈论你的代码
    【解决方案6】:

    怎么样:

    String concat = objList.stream().reduce(",", String::concat);
    System.out.println(concat);
    

    【讨论】:

    • 谢谢你的回答,但你能帮我找到一种方法来解决这个问题吗?
    • ,PeterJamesBart 出来了,我得到了,这是错误的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-14
    • 2018-08-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多