1

Here is what I have, I want to sort in descending a the value in the entry.

Map<String, Outer> outer = Input
                          .entrySet()
                          .stream
                          .collect(toMap(Map.Entry::getKey, entry->{
                           List<Outer> inner = entry
                                    .getValue()
                                    .stream()
                                    .sorted(Comparator.comparingDouble(???))
                              })) ... (more lines of code.)

How to write a Comparator with sorted. If want to do the following inside sorted

if (o1.getSomething() > o2.getSomething())
     return -1;
if (o1.getSomething() < o2.getSomething())
     return 1;
return 0;

After getting the List and sorting it works for me.

inner.sort((Outer o1, Outer o2) -> {
if (o1.getSomething() > o2.getSomething())
         return -1;
    if (o1.getSomething() < o2.getSomething())
         return 1;
    return 0;
});

But is there a way to use stream.sorted( " use the same comparator logic here") inside entry.

Entry is an ArrayList, with bunch of values.

entry:[{w:1},{w:2},{w:3},{w:4}];

So I want to reverse sort this, to be as follows:

entry:[{w:4},{w:3},{w:2},{w:1}];

so the final list I get is a sorted in reverse order one.

sry for the confusion.

patz
  • 1,306
  • 4
  • 25
  • 42

5 Answers5

2

You can define the Comparator and then use stream.sorted() as shown below with inline comments:

//Define comparator Lamda exp for Outer class
Comparator<Outer> outerComparator = (o1, o2) -> {
         if (o1.getValue() > o2.getValue())
                return -1;
          else if (o1.getValue() < o2.getValue())
                return 1;
            else 
              return 0;
   };


Map<String, Outer> output = Input.entrySet(). //get elements
        stream(). //get elements
        sorted( //sort elements by passsing outerComparator
        Map.Entry.<String, Outer>comparingByValue(outerComparator)
        .reversed())//reverse for descending order
        .collect(Collectors.toMap(Map.Entry::getKey, 
        Map.Entry::getValue));//collect to Map object
Vasu
  • 21,832
  • 11
  • 51
  • 67
1

If you're just trying to get the values of the Map and place them into a sorted List, you could do the following:

Map<String, Element> elMap = new HashMap<>();
elMap.put("3", new Element("3"));
elMap.put("2", new Element("2"));
elMap.put("1", new Element("1"));

List<Element> elList = elMap.values()
        .stream()
        .sorted((e1, e2) -> {
            return e1.getSortField().compareTo(e2.getSortField());
        })
        .collect(Collectors.toList());
System.out.println(elList);

In here, Element is a simple POJO with a single String field called sortField. sorted() takes a Comparator. Which is a functional interface with 2 parameters and an int return type. Which was ok for the given lambda.

You could also let your element implement Comparable. Then you could do:

List<Element> elList = elMap.values()
        .stream()
        .sorted()
        .collect(Collectors.toList());

With the Element implementing the correct Interface

static class Element implements Comparable<Element> {
    //Constructor, field, getters
    @Override
    public int compareTo(Element o) {
        return this.sortField.compareTo(o.sortField);
    }
}

EDIT:

its a list inside the Map, that I am trying to sort. And trying to sort it in the chain itself.

This could be interpreted as the following:

Map<String, List<Element>> collected = elMap.entrySet()
        .stream()
        .peek(entry -> System.out.println("Performing arbitrary Map operations"))
        .collect(Collectors.toMap(Map.Entry::getKey, entry -> {
            return entry.getValue()
                    .stream()
                    .sorted(Comparator.comparingDouble(Element::getWeight))
                    .collect(Collectors.toList());
        }));

collected.entrySet()
        .forEach(entry -> {
            System.out.println(entry.getKey() + " : " + entry.getValue());
        });

You stream over the ´Map.entrySet()´ and do whatever you want with it. When collecting it back into a different Map as per your question, you can stream and collect your List again with the examples from above.

Jaims
  • 1,515
  • 2
  • 17
  • 30
  • I tried something similar before, but when I tried evaluating e1 it wasn't able to find local variable. .sorted((e1, e2)-> { if (e1.getWeight() > e2.getWeight()) return -1; if (e1.getWeight() < e2.getWeight()) return 1; return 0; }) – patz Mar 31 '17 at 17:59
  • I cant use compareTo because the return type is double. – patz Mar 31 '17 at 18:00
  • @patz your `Comparator` works fine for me. Also note there's `Double.compare(e1.getWeight(), e2.getWeight())`. Note that i'm streaming over the values. Not over the entries. Otherwise you'd have to get the value of the entry first. – Jaims Mar 31 '17 at 18:02
  • Does not work .sort((e1, e2) -> Comparator.comparingDouble(e1.getWeight(), e2.getWeight())) – patz Mar 31 '17 at 18:11
  • when I do this .sort((e1, e2) -> Double.compare(e1.getWeight(), e2.getWeight())) I get result undefined – patz Mar 31 '17 at 18:12
  • @patz If you'd like to use the `Comparator` utility class, `comparingDouble` takes a `ToDoubleFunction` as parameter (1 input of type `T` and `Double` output. That would be `.sorted(Comparator.comparingDouble(el -> el.getWeight()))`. Also, your `Outer` in your question. Is this a list you'd like to be sorted inside your `Map` or are you trying to get rid of your `Map` all together and just get the `List`? – Jaims Mar 31 '17 at 18:18
  • its a list inside the Map, that I am trying to sort. And trying to sort it in the chain itself. – patz Mar 31 '17 at 18:21
  • @patz I have updated the answer as per your comment. Hope that clears some stuff up regarding to your case – Jaims Mar 31 '17 at 18:30
  • @patz No problem. Don't forget to upvote the answers that helped you and accept the ones that solved your problems. – Jaims Mar 31 '17 at 18:34
  • sure yes I will. I was checking if that actually works. Not sure if this actually works - Element::getWeight – patz Mar 31 '17 at 18:36
1

As far as I can tell your question is really just how to create a sorted list as the value in your map, with sorting based on the return of getSomething.

entry.getValue().stream()
    .sorted(Comparator.comparing(Outer::getSomething))
    .collect(toList())

will return the list sorted according to getSomething. If that method returns a double then you could use comparingDouble(Outer::getSomething) to avoid boxing the value.

sprinter
  • 27,148
  • 6
  • 47
  • 78
1

If I'm guessing correctly, you want to order all your values (which are lists) according to a given comparator.

If this is the case, you don't need to create a stream at all. Using Map's replaceAll method should suffice:

// Orders Outer elements according to Outer's getSomething method 
// in descendant order (assumes getSomething returns a double value)
Comparator<Outer> yourComparator = 
    Comparator.comparingDouble(Outer::getSomething).reversed();

yourMap.replaceAll((k, v) -> {
        Collections.sort(v, yourComparator);
        return v;
    });

This utilizes the Collections.sort method, which takes a list and a comparator.

fps
  • 33,623
  • 8
  • 55
  • 110
  • well if I had to do this I could just sort on the list. as list itself has a sort method. I am trying to sort before the list is created. the entries in the list should itself be sorted. – patz Mar 31 '17 at 18:49
  • the Map has K,V and my list consists of this Values V. but there are not sorted in the order I want. one way is to sort them after they are inserted into the list or before inserting sort them. and I am trying to do the later. – patz Mar 31 '17 at 18:50
  • @patz Then please clarify where the elements of the list come from, i.e. are they inside a map? I mean where the `Outer` elements come from. – fps Mar 31 '17 at 18:51
  • @patz How are you grouping the values? It seems from what I can see in your question that each key is mapped to a single element only, so how can that single element become a list? – fps Mar 31 '17 at 18:53
  • Simplified : entry.getValue() gives me this entry:[{w:1},{w:2},{w:3},{w:4}]; what I want to achieve. entry.getValue().stream().sorted("code here ") to give me entry:[{w:4},{w:3},{w:2},{w:1}]; – patz Mar 31 '17 at 18:55
  • @patz I don't understand, if you already have a map that has each key mapped to a list, then why does my answer not solve your problem? If, on the contrary, you want to have this map of lists created with each list in reverse order from the beginning, then you should show us how you are creating this initial map. – fps Mar 31 '17 at 18:59
0

So here is the answer that worked for me.

.sorted(reverseOrder(comparingDouble(Input::getSomething)))

Thanks everyone,

patz
  • 1,306
  • 4
  • 25
  • 42