Home > Blockchain >  Sort a list based on member field’s value’s position in another list
Sort a list based on member field’s value’s position in another list

Time:01-14

I have a Person with fields score(int), name(String) and country(String)

1, Jane , Spain
2, James, Italy
1, John , Italy
2, Peter , England
3, Thomas , England
3, Martin , England

Now I provide another List of Strings which represent country names say : [Italy, Spain, Norway, England, Germany]

My requirement is to sort the Person list based on scores first, if they have the same score then sort by the country names provides in the country names list. If country names also match then sort by person name.

So finally the person objects should be returned in this order:

1, John, Italy
1, Jane, Spain
2, James, Italy
2, Peter, England
3, Martin, England
3, Thomas, England

Here is the code I am trying:

public static List<Person> sortRecords(List<Person> people, List<String> countries) {
    people.sort((p1, p2) -> {
        int compare = p1.getScore() - p2.getScore();
        if(compare == 0) {
            compare = // how to compare by country names based on provided List<String> countries
            if(compare == 0) {
                compare = p1.getName().compareTo(p2.getName());
            }
        }
        return compare;
    });
}

I am stuck at comparing by country names.

CodePudding user response:

Use List.indexOf

public static List<Person> sortRecords(List<Person> people, List<String> countries) {
    people.sort((p1, p2) -> {
        int compare = p1.getScore() - p2.getScore();
        if(compare == 0) {
            compare = countries.indexOf(p1.getCountry()) - countries.indexOf(p2.getCountry());
            if(compare == 0) {
                compare = p1.getName().compareTo(p2.getName());
            }
        }
        return compare;
    });
    return people;
}

Note that as the sort is done inplace, you don't need to return the list, then using java.util.Comparator you can do some nice thing

public static void sortRecords(List<Person> people, List<String> countries) {
    people.sort(
         Comparator.comparingInt(Person::getScore)
                   .thenComparingInt(person -> countries.indexOf(person.getCountry()))
                   .thenComparing(Person::getName)
    );
}

CodePudding user response:

I would use a stable sorting algorithm to sort the list by name, then by country, and then by score. See https://www.geeksforgeeks.org/stability-in-sorting-algorithms/

import java.util.*;
class Record {
    int score; String name; String country;
    Record(int s, String n, String c){ score=s; name=n; country=c; }
    public String toString(){ 
      return String.format("[%d, %s, %s]", score, name, country);
    }
}
public class Main{
    public static void main(String[] args) {
        Record[] records = {
              new Record(1, "Jane" ,   "Spain"),
              new Record(2, "James",   "Italy"),
              new Record(1, "John" ,   "Italy"),
              new Record(2, "Peter",   "England"),
              new Record(3, "Thomas",  "England"),
              new Record(3, "Martin", "England")
        };
        Comparator<Record> byScore   = (r1,r2)->r1.score-r2.score;
        Comparator<Record> byCountry = (r1,r2)->r1.country.compareTo(r2.country);
        Comparator<Record> byName    = (r1,r2)->r1.name.compareTo(r2.name);

        System.out.println("===before====");
        Arrays.stream(records).forEach(System.out::println);
        
        Arrays.sort(records, byName); 
        Arrays.sort(records, byCountry);     
        Arrays.sort(records, byScore);
        
        System.out.println("===after====");
        Arrays.stream(records).forEach(System.out::println);
    }
}

Output

===before====
[1, Jane, Spain]
[2, James, Italy]
[1, John, Italy]
[2, Peter, England]
[3, Thomas, England]
[3, Martin, England]
===after====
[1, John, Italy]
[1, Jane, Spain]
[2, Peter, England]
[2, James, Italy]
[3, Martin, England]
[3, Thomas, England]
  •  Tags:  
  • Related