3

I have a Data Set something like this:

85 [Italy, France]    
95 [Italy]
91 [Israel, Jordan]
85 [France, Italy, Switzerland]
80 [USA]
84 [Mongolia, China]
95 [Antarctica]
84 [African Union]
82 [Argentina]
95 [Tibet, Nepal]
...

Which I have sorted based on based on the integers using below code (defining the class model):

public class Wonder implements Comparable<Wonder> {
    int hostility;
    List<String> countries;
    //some other data members

    //constructor
    //getters

    @Override
    public int compareTo(Wonder other) {
        if(hostility == other.hostility) {
            return 0;
        } else if(hostility < other.hostility) {
            return -1;
        } else if(hostility > other.hostility) {
            return 1;
        } else {
            return 0;
        }
    }
}

Sorting Code (PS: getAllData method will return a list of wonders, loading from Text file):

List<Wonder> wonders = getAllData(filePath);
wonders.sort((c1,c2)->c1.compareTo(c2));
Collections.reverse(wonders); // ordering highest to lowest 

After sorting the Data Set (sorted based on integers) looks something like this:

95 [Antarctica]
95 [Italy]
95 [Tibet, Nepal]
91 [Israel, Jordan]
85 [France, Italy, Switzerland]
85 [Italy, France]
84 [Mongolia, China]
84 [African Union]
82 [Argentina]
80 [USA]
...

Now, there is need to sort newly generated Data Set to alphabetically which are the List of countries (strings). For example, in new Data Set there're two records with the same integer 84 (1st integer has country Mongolia and 2nd integer has country African Union), so the second record should come first as African Union is alphabetically before the Mongolia.

...
84 [African Union]
84 [Mongolia, China]
...

Question: How to sort a List of integers based on a List of strings?

  • Possible duplicate of [In Java how do you sort one list based on another?](https://stackoverflow.com/questions/18129807/in-java-how-do-you-sort-one-list-based-on-another) – Avi Aug 02 '19 at 18:19
  • *FYI:* Since `hostility` is an `int`, your `compareTo` method can be shortened to `return Integer.compare(this.hostility, other.hostility)`. --- Sorting of a list of `Comparable` objects in descending order can be written as `wonders.sort(Comparator.reverseOrder());`, so no need for `sort()` + `reverse()`. – Andreas Aug 02 '19 at 18:48
  • Shouldn't you first sort `countries` and then sort by `hostility` and at end by country name. I looked at your text file and for `hostility = 69` there is `69 [Japan]` and `69 [USA, Canada]`. It will not be same order if you have `69 [Canada, USA]`, for example. – Freeman Aug 02 '19 at 20:01
  • @Freeman but list is sorted correctly using below answer . If you have an answer then please post it blow. Thanks! –  Aug 03 '19 at 05:41

3 Answers3

1

You can further specialize the compareTo function to enact a secondary comparison. I'm assuming that every list contains at least one country; if such is not the case, you must handle empty lists. The altered compareTo is as so:

@Override
public int compareTo(Wonder other) {
    if(this == other) {
        return 0;
    } else if(hostility < other.hostility) {
        return -1;
    } else if(hostility > other.hostility) {
        return 1;
    } else {
        return -countries.get(0).compareTo(other.countries.get(0));
    }
}

Alternatively you may be looking for this:

wonders.sort(Comparator.comparingInt(Wonder::getHostility).reversed()
    .thenComparing(wonder -> wonder.getCountries().get(0)));
//don't reverse afterwards!

according to @Andrew's style

A repl.it with the best of all answers

Avi
  • 2,611
  • 1
  • 14
  • 26
  • Did you check that no list is empty? – Avi Aug 02 '19 at 18:37
  • List wonders = getAllData(filePath); System.out.println(wonders.stream().anyMatch(w -> w.countries.size() == 0)); This will tell you if you have any empty country list – Avi Aug 02 '19 at 18:42
  • Right! I forgot that you were reversing it. Then, just change the last line to return negative countries.get(0).compareTo(other.countries.get(0)); – Avi Aug 02 '19 at 18:44
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/197404/discussion-between-avi-and-5377037). – Avi Aug 02 '19 at 18:59
  • @5377037 it's weird because it was a part of my answer – Andrew Tobilko Aug 02 '19 at 19:28
  • @AndrewTobilko re-post your answer. you deleted it. –  Aug 02 '19 at 19:30
  • 2
    @AndrewTobilko When you reversed, you reversed the entire comparator (reversed() after thenComparing()). I reversed only the integer (hostility-based) comparator (reversed() before thenComparing()). – Avi Aug 02 '19 at 19:37
  • 1
    The first condition check of the `if` shouldn't be present. `hostility` is either greater or lower, and if it's equal, you compare countries (which might be greater, lower or equal)... – fps Aug 02 '19 at 20:01
  • Yes; it should actually be if(this == other) { return 0; }, and I'll edit the answer to reflect this. However, the "best" code is within the repl.it. – Avi Aug 02 '19 at 20:05
1

If you do, what accepted answer suggested:

wonders.sort(Comparator.comparingInt(Wonder::getHostility).reversed()
    .thenComparing(wonder -> wonder.getCountries().get(0)));

on text file, that you provided, you will get next result:

95 [Antarctica]
95 [Italy]
95 [Tibet, Nepal]
91 [Israel, Jordan]
85 [France, Italy, Switzerland]
85 [Italy, France]
84 [African Union] 
84 [Mongolia, China]
82 [Argentina]
80 [USA]
70 [Australia]
69 [Japan]
69 [USA, Canada]
65 [The Hawaiian Islands]
65 [USA]
55 [Russia]
50 [Brazil, Argentina]
19 [Tanzania]
17 [Northern Ireland]
16 [China]
12 [African Union]
10 [Australia]
10 [Brazil]
2 [USA]

But, if you first sort countries and then do accepted answer:

wonders.forEach(wonder -> Collections.sort(wonder.getCountries()));
wonders.sort(Comparator.comparingInt(Wonder::getHostility).reversed().
    thenComparing(wonder -> wonder.getCountries().get(0))); 

then you will get:

95 [Antarctica]
95 [Italy]
95 [Nepal, Tibet]
91 [Israel, Jordan]
85 [France, Italy] 
85 [France, Italy, Switzerland]
84 [African Union]
84 [China, Mongolia]
82 [Argentina]
80 [USA]
70 [Australia]
69 [Canada, USA]
69 [Japan]
65 [The Hawaiian Islands]
65 [USA]
55 [Russia]
50 [Argentina, Brazil]
19 [Tanzania]
17 [Northern Ireland]
16 [China]
12 [African Union]
10 [Australia]
10 [Brazil]
2 [USA]

Pay attention on hostility with values 85 and 69 in these two list. The order is not the same. Don't know if this is relevant to you.

P.S. If you implemente Comparable#compareTo(), you should also implement equals() because there is contract between them:

(x.compareTo(y) == 0) == (x.equals(y))

If this is not the case you should make note: This class has a natural ordering that is inconsistent with equals.

Last thing:

compareTo() must throw NullPointerException if current object get compared to null object as opposed to equals() which return false on such scenario.

Freeman
  • 232
  • 1
  • 2
  • 11
  • I see in my case, sorting the countries first is not a solution. BTW, thanks for your answer. up voted –  Aug 03 '19 at 12:43
0

Not sure I understood what is your issue. Does below pseudo code solve your problem ?

@Override
public int compareTo(Wonder other) {
    if(hostility == other.hostility) {
       // let's compare the strings list when hostility integer are equals (84, 84)
       String firstOtherCountry = other.countries.SortAlphabetically().get(0);           
       // we sort the countries list for current line and other wonder
       // you compare alphabetically first element of each list : 
       // return 1, 0 or -1 here.
    } else if(hostility < other.hostility) {
        return -1;
    } else if(hostility > other.hostility) {
        return 1;
    } else {
        return 0;
    }
}

How can I sort a List alphabetically?

Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
Poutrathor
  • 1,990
  • 2
  • 20
  • 44