简体   繁体   中英

Sort a map based on value which is an arraylist java 8

I have a Hashmap map<String, List<Student>> .

Student {
  String name;
  List<Date> absentDates;
}

Key Values pairs as follows:

["Class1",<Student1  absentDates = [02/11/2010, 02/09/2010]><Student2  absentDates = [02/10/2010]>]
["Class2",<Student3  absentDates = [02/12/2010]>]
["Class3",<Student4  absentDates = null>]

How can I sort this map using java 8 steams as follows, based on map value ie, List.get(0).getAbsentDates().get(0) ie, a nullable absentDates of first Student object in each list

Expected output is

["Class2",<Student3  absentDates = [02/12/2010]>]
["Class1",<Student1  absentDates = [02/11/2010, 02/09/2010]><Student2  absentDates = [02/10/2010]>]
["Class3",<Student4  absentDates = null>]

Steps I followed.

  1. Map<String, List> Stream through the entrySet
  2. convert to class MapValues{Key,List}. MapValue is the Custom wrapper class created to hold key and value
  3. Implement Comaparator for MapValues based on stundents.get(0).getAbsentDates().get(0) and also handle null in comaprator
  4. Collect using Collectors.toMap to preserve the order use LinkedHashMap

In Short the

Map<String, List<Student>> newmap = map.entrySet()
                                                .stream()
                                                .map(e -> new MapValues(e.getKey(), e.getValue()))
                                                .sorted(new MapValuesComp())
                                                .collect(Collectors.toMap(
                                                 MapValues::getKey, MapValues::getStdns, 
                                                             (e1, e2) -> e1, 
                                                            LinkedHashMap::new));
public class CustomMapSorting {
    public static void main(String[] args) throws ParseException {

        Map<String, List<Student>> map = new HashMap<>();
        SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy");
        // Class1 Stundent1
        Date s1Date1 = format.parse("02/11/2010");
        Date s1Date2 = format.parse("02/09/2010");

        Date[] s1absentDates = { s1Date1, s1Date2 };
        Student s1 = new Student("Student1", Arrays.asList(s1absentDates));
        // Class1 Stundent2
        Date s2Date1 = format.parse("02/10/2010");

        Date[] s2absentDates = { s2Date1 };
        Student s2 = new Student("Student2", Arrays.asList(s2absentDates));

        // Class2 Stundent3

        Date s3Date1 = format.parse("02/12/2010");

        Date[] s3absentDates = { s3Date1 };
        Student s3 = new Student("Student3", Arrays.asList(s3absentDates));

        // Class3 Stundent4

        Student s4 = new Student("Stundent4", null);

        List<Student> class1SundLst = Arrays.asList(s1, s2);
        map.put("Class1", class1SundLst);
        map.put("Class2", Arrays.asList(s3));
        map.put("Class3", Arrays.asList(s4));

        Map<String, List<Student>> newmap = map.entrySet()
                                                .stream()
                                                .map(e -> new MapValues(e.getKey(), e.getValue()))
                                                .sorted(new MapValuesComp())
                                                .collect(Collectors.toMap(MapValues::getKey, MapValues::getStdns, (e1, e2) -> e1, LinkedHashMap::new));
        //Printing the sorted values
        newmap.entrySet().stream().forEach(e -> System.out.println(e.getKey() + " : " + e.getValue().get(0).absentDates));

    }

}

class MapValues {
    String key;
    List<Student> stdns;

    public MapValues(String key, List<Student> stdns) {
        super();
        this.key = key;
        this.stdns = stdns;
    }

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public List<Student> getStdns() {
        return stdns;
    }

    public void setStdns(List<Student> stdns) {
        this.stdns = stdns;
    }

    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return key;
    }

}

class MapValuesComp implements Comparator<MapValues> {

    public int compare(MapValues o1, MapValues o2) {
        if (o1.stdns.get(0).absentDates == null) {
            return (o2.stdns.get(0).absentDates == null) ? 0 : 1;
        }
        if (o2.stdns.get(0).absentDates == null) {
            return 1;
        }
        return o2.stdns.get(0).absentDates.get(0).compareTo(o1.stdns.get(0).absentDates.get(0));

    }

}

class Student {
    String name;
    List<Date> absentDates;

    public Student(String name, List<Date> absentDates) {
        super();
        this.name = name;
        this.absentDates = absentDates;
    }

    @Override
    public String toString() {
        if (absentDates == null)
            return null;
        SimpleDateFormat format = new SimpleDateFormat("dd/mm/YYYY");
        return format.format(absentDates.get(0));
    }

}

I tried a inline solution using lambdas from the answer posted using @Rono. Just a improved version of his solution.

Map<String, List<Student>> res = map.entrySet()
        .stream()
        .sorted((o1, o2) -> {
            if (o1.getValue().get(0).absentDates == null) {
                return (o2.getValue().get(0).absentDates == null) ? 0 : 1;
            }
            if (o2.getValue().get(0).absentDates == null) {
                return 1;
            }
            return o2.getValue().get(0).absentDates.get(0).compareTo(o1.getValue().get(0).absentDates.get(0));
        }).
        collect(Collectors.toMap(Map.Entry::getKey, 
                Map.Entry::getValue,(e1, e2) -> e1, 
                LinkedHashMap::new));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM