Java 8 Streams find element and add it to the star

2019-05-14 05:43发布

问题:

I am wondering if this is possible to solve this problem with one line using Java Streams : i need to find a String in a list of strings and create another list where the search string (if found) will be the first string on the new List and then the rest of the String values

For Eg:

List<String> oldList = Arrays.asList("Avacado", "Apple", "Orange", "Chocolate");

So now if if search using say a filter "Chocolate" its should return a new list which will contain the elements in order "Chocolate", "Avacado", "Apple", "Orange".

List<String> newList =  oldList.stream().filter(i -> i.equals("Chocolate")).collect(Collectors.toList()) ???

回答1:

You're asking for a solution using Stream. This is one:

    List<String> sorted = oldList.stream()
            .sorted(Comparator.comparing("Chocolate"::equals).reversed())
            .collect(Collectors.toList());
    System.out.println(sorted);

And it gives:

[Chocolate, Avacado, Apple, Orange]

So only "Chocolate" was moved at first index.

But actually yon don't need a Stream. The list itself is enough:

oldList.sort(Comparator.comparing("Chocolate"::equals).reversed());
System.out.println(oldList);

The result is

[Chocolate, Avacado, Apple, Orange]

... the same.

EDIT:
I've updated my answer as @Holger pointed out that it violated the contract of Comparator.compare(o1,o2). I'm using the solution Holger suggested in his comment. So he should be upvoted as I struggled two times to get a correct solution.

This approach maps each string to a boolean value which states whether the string is equal to "Chocolate". In case of equality Boolean.compare(x,y) will return 1 for x and -1 for y if the other string is not equal to "Chocolate". If x and y are equal to "Chocolate" the result is 0.
As we want to move "Chocolate" to the first index it's index has to decrease. Thus a reveresed comparator (1 => -1 and -1 => 1) is needed.



回答2:

Your requerement is basically about sorting the list so you might use the sort method:

List<String> newList =  
    oldList.stream()
           .sorted((i1,i2) -> i1.equals("Chocolate")?
                           -1: // untested, so may be the other way around...
                           i2.equals("Chocolate")?
                             1:
                             i1.compareTo(i2))
           .collect(Collectors.toList())

[edit:] Thanks to @Holger we can somplify to:

List<String> newList =  
    oldList.stream()
           .sorted(Comparator.comparing("Chocolate"::equals).reversed())
           .collect(Collectors.toList())


回答3:

You can do it after collecting list without targetElement and then add first postion of new list.

List<String> newList =  oldList.stream().filter(i -> !i.equals("Chocolate")).collect(Collectors.toList());
    if(oldList.size() != newList.size()){
        newList.add(0,"Chocolate");
    }


回答4:

I personally don't think that Streams are suitable for this task. A procedural way to do this is more readable in my mind.

Here's my solution. The commented code is the procedural way of doing so. I used integers for convenience but strings are the same.

        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
//        int index = list.indexOf(3);
//        ArrayList<Integer> resultList = new ArrayList<>();
//        resultList.add(list.get(index));
//        resultList.addAll(list.subList(0, index));
//        resultList.addAll(list.subList(index + 1, list.size()));
        List<Integer> resultList = Stream.concat(Stream.of(3), list.stream().filter(x -> x == 3)).collect(Collectors.toList());
        System.out.println(resultList);