Split string into list, sort and maintain order

Viewed 629

I have a string that is pipe separated and I wanted to spilt it into a list and sort it in the reverse order.

But I see that the order is not maintained. Whats the problem here ?

String str = "Chicago|Indianapolis|Boston|Houston";
List<String> splitList= Stream.of(str.split("\\|"))
                .map(String::trim)
                .sorted(Collections.reverseOrder())
                .limit(30)
                .collect(toList());

//Expected [Houston,Boston,Indianapolis,Chicago]
//Got [Indianapolis,Houston,Boston,Chicago]
3 Answers

Try with below

    String str = "Chicago|Indianapolis|Boston|Houston";
    List<String> splitList= Arrays.asList(str.split("\\|"));
    Collections.reverse(splitList);
    System.out.println(splitList);

Output is:

[Houston, Boston, Indianapolis, Chicago]

You can use the following way to do that

String cityStr = "Chicago|Indianapolis|Boston|Houston";
List<String> cityList = Arrays.asList(cityStr.split("\\|"))
.stream().sorted( Comparator.reverseOrder()).collect( Collectors.toList());

The Problem

Your code is that you are sorting the elements in reverse order. Thus, it maintains the reverse sorting order but not the order in which they were present in the string.

The Idea

The Stream operations you need do not store the intermediate result for you to reverse. You can iterate on the elements and keep on adding them to the beginning of the Collection which essentially reverses the order.

List vs Deque

ArrayList‘s addFirst(...) is O(n^2) time. So, use Deque instead which is efficient in adding elements to the front.

Code:

String str = "Chicago|Indianapolis|Boston|Houston";
Deque<String> splitList = Stream.of(str.split("\\|"))
    .map(String::trim)
    .collect(Collector.of(
        ArrayDeque::new,
        (deq, t) -> deq.addFirst(t),
        (d1, d2) -> {
            d2.addAll(d1);
            return d2;
        }));
System.out.print(splitList);

Output:

[Houston, Boston, Indianapolis, Chicago]

Pro Tip:

In a capacity-restricted environment, you can use the method offerFirst(...) which will only insert the element if it does not violate the capacity restrictions. Will need exception handling.

Related