Java 8中使用forEach lambda循环检查List的范围

7

我希望学习如何在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(","));

不过我想知道如何检查范围并在我的第一段代码中去掉逗号。


4
拜托,当您将其投票降低时,请说明原因?这个问题有什么问题吗? - user3674428
...什么?你有点困惑吗? - specializt
不要使用命令式风格,因为这里不清楚如何检查范围。我只想去掉最后一个逗号。 - user3674428
6个回答

6

在处理流项目时,没有直接获取流项目索引的方式。不过有几种替代方法。

其中一种方式是通过索引运行流,然后从列表中获取元素。对于每个元素,它将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来特殊处理最后一个元素。这需要单独的打印语句,虽然不太美观:
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收集器的目的是为了为您完成这种丑陋和恼人的特殊情况处理,以便您不必自己处理。


如果你正在流式传输列表本身的元素,那么你是做不到的。如果你有一个列表,你可以使用IntStream.range创建一个索引流,然后在映射器中使用list.get(i)list.get(i+1) - Stuart Marks
没问题,但还是谢谢你。你的回答引导我想到了那个问题,所以我也要非常感谢你。 :) - user3674428
我能通过电子邮件与您保持联系吗? - user3674428
请看一下这个问题,告诉我如果我有8个元素,如何让它更好。基本上适用于奇数和偶数个元素。 - user3674428
@user3674428 抱歉,我已经收到了超出我的处理能力的电子邮件。 :-) 请查看我对Eran在那个问题上的回答的评论。 - Stuart Marks
显示剩余2条评论

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。在limit之前,流的大小是列表大小的两倍,因为flatMap使其长度加倍。

请注意,如果列表为空,则会抛出IllegalArgumentException,因为传递给limit的值将为-1。如果可能,请先检查此问题。


请问您能解释一下flatMap吗? - user3674428
http://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#flatMap-java.util.function.Function- - Alex - GlassEditor.com
1
"Peter,你能告诉我逗号带引号和不带引号的区别吗?" - user3674428
1
不要使用引号来分隔元素,它们不在流中。 - Alex - GlassEditor.com
1
有趣的是它是如何移除它的? - user3674428
1
为什么要乘以二? - user3674428

1
我们也可以尝试使用流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()>0){ returnData.stream().limit(returnData.size()-1).forEach(s->System.out.print(s+",")); returnData.stream().skip(returnData.size()-1).forEach(s->System.out.print(s));} - Low

1
什么意思:
String concat = objList.stream().reduce(",", String::concat);
System.out.println(concat);

谢谢您的回答,但您能否帮我找到一种使用映射解决这个问题的方法? - user3674428
我得到的输出是PeterJamesBart,但是它是错误的。 - user3674428

0
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是最后一个项目?我想要一些通用的东西。 - user3674428
如果您想要使用确切的位置进行操作,您将需要使用Map——键为数字,值为字符串。例如,具有最高值的键将产生您的最后一个映射值。 - specializt
请您在回答中贴上您的代码,这样我就可以运行它了吗? - user3674428
1
我相当确定我的小例子会按原样工作...但既然你这么客气地问了,我会在我的工作场所使用开发环境来测试它...请稍等片刻。 - specializt
//这是一个关于编程的内容,请将其从英文翻译成中文。仅返回翻译后的文本:不要在答案部分中放置您的代码,而是将它放在注释部分中 - user3674428
显示剩余2条评论

0

试一下这个,

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接