简体   繁体   中英

Checking range of List in forEach lambda loop Java 8

I want to learn how I can check the range of a list in java 8.

For example,

My Code:

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

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

My out come is

    Peter,James,Bart,

but I want to know how I can get rid of the last ,

Note: I know I must use filter here , yet I do not know how and I know there is another way to solve this which is as follows

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

yet I want to know how to check the range and get rid of , in my first code.

You could do this:

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

flatMap replaces each element of the original stream with the elements in the streams returned from the mapping function.

So if your stream was originally

"Peter" - "James" - "Bart"

The above mapping function changes it to

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

Then the limit removes the last "," by shortening the stream to be at most the length of the value that is passed to it, which in this case is the size of the stream - 1. The size of the stream was 2 * the size of the list before limit because flatMap doubled it's length.

Note that this will throw an IllegalArgumentException if the list is empty, because the value passed to limit will be -1. You should check for this first if that is a possibility.

There's no direct way to get the index of a stream item while you're processing the items themselves. There are several alternatives, though.

One way is to run the stream over the indexes and then get the elements from the list. For each element index it maps i to the i'th element and appends a "," for all indexes except the last:

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

A second, more concise variation is to special case the first element instead of the last one:

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

A third way is to use the particular reduce operation that is applied "between" each two adjacent elements. The problem with this technique is that it does O(n^2) copying, which will become quite slow for large streams.

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

A fourth way is to special-case the last element by limiting the stream to length n-1. This requires a separate print statement, which isn't as pretty though:

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

A fifth way is similar to the above, special-casing the first element instead of the last:

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

Really, though the point of the joining collector is to do this ugly and irritating special-casing for you, so you don't have to do it yourself.

What about:

String concat = objList.stream().reduce(",", String::concat);
System.out.println(concat);
objList.stream().filter(s -> { return !s.equals("Bart") })

This will reduce the stream to the strings which are NOT equal to Bart

And this will print the last value of a map :

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

We can also try using limit and skip methods of stream API to this problem. Here is my try to this problem.

    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 is a List of Integers having values 2,4,7,14. The output will look like 2,4,7,14

try this,

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM