Search code examples
javaarraysalgorithmhashmap

How to store data in list of objects of an object?


I have the following code which group the users with same age and highest score among them. I have now instead of Map<Person, List<String>> one object called Person and in the person class there Map Map<String,Double> nameScoreTogether;. I need to store the output in the map of the person object with its informations(name and the corresponding score), so how can i change the code accordingly ?

Input: In data type of Map<Person, String>:

    {Person has at Age: 12 (Score: 50)
    =alex,
     Person has at Age: 16 (Score: 50)
    =miki, 
    Person has at Age: 5 (Score: 100)
    =shi, 
    Person has at Age: 4 (Score: 50)
    =rafi, 
    Person has at Age: 1 (Score: 50)
    =sharbel, 
    Person has at Age: 5 (Score: 0)
    =thomas, 
    Person has at Age: 14 (Score: 60)
    =thomy, 
    Person has at Age: 14 (Score: 50)
    =angelos,
     Person has at Age: 11 (Score: 50)
    =musti, 
    Person has at Age: 11 (Score: 100)
    =aloo,
     Person has at Age: 2 (Score: 50)
    =evi}  

The Expected output is:

    Person(score=50.0, age=1) - [sharbel=50.0]
    Person(score=100.0, age=11) - [aloo=100.0, musti=50.0]
    Person(score=50.0, age=12) - [Alex=50.0]
    Person(score=60.0, age=14) - [thomy=60.0, angelos=50.0]
    Person(score=50.0, age=2) - [evi=50.0]
    Person(score=100.0, age=5) - [shi=100.0, Thomas=5.0]
    Person(score=50.0, age=4) - [rafi=50]
    Person(score=50.0, age=16) - [miki=50]

Try code: but now I have List<Person> which has Map<String,Double>

    Map<Person, List<String>> result = origin.entrySet().stream()
        .collect(Collectors.groupingBy(e -> e.getKey().getAge())).entrySet().stream()
        .collect(Collectors.toMap(
            e -> e.getValue().stream()
                .map(Map.Entry::getKey)
                .max(Comparator.comparing(Person::getScore))
                .get(),
            e -> e.getValue().stream()
                .map(Map.Entry::getValue)
                .collect(Collectors.toList()))
        );

Class Person:

    public class Person {
        int Age;
        int lineScoreMax;
        Map<String, Double> nameScoreTogether;
    }

Solution

  • I have changed the Person class as

    public class Person {
        int age;
        double lineScoreMax;
        Map<String, Double> nameScoreTogether;
    
        Person(int age, double score) {
            this.age = age;
            this.lineScoreMax = score;
        }
    
        Person(int age, double score,  Map<String, Double> nameScoreTogether) {
            this.age = age;
            this.lineScoreMax = score;
            this.nameScoreTogether = nameScoreTogether;
        }
    
        public int getAge() {
            return age;
        }
    
        public double getLineScoreMax() {
            return lineScoreMax;
        }
    }
    

    I have added a new three parameter constructor.

    Map<Person, String> origin = new HashMap();
    //Populate origin
    
    Map<Integer, List<Map.Entry<Person, String>>> ageToListOfPersonNames = origin.entrySet()
                .stream()
                .collect(Collectors.groupingBy(entry -> entry.getKey().getAge()));
    
    List<Person> persons = ageToListOfPersonNames.entrySet()
            .stream()
            .map(entry -> new Person(entry.getKey(),
                    //Find the max score for an age
                    entry.getValue()
                         .stream()
                         .map(Map.Entry::getKey)
                            .max(Comparator.comparingDouble(Person::getLineScoreMax))
                            .map(Person::getLineScoreMax)
                            .orElse(0D),
    
                    //Find the map of name to score
                    entry.getValue()
                            .stream()
                            .collect(Collectors.toMap(Map.Entry::getValue,
                                    personNameEntry -> personNameEntry.getKey().getLineScoreMax()))
                ))
            .collect(Collectors.toList());
    

    First, I map the input to a map of age to list of person, name entries.

    Next, I stream it and compute the max score and map of person name to individual score and pass them as arguments to the Person constructor. Finally, I collect the individual Person objects as a list.

    Note: This assumes that person name is unique.


    UPDATE 1: From your comment,

    [..] what if i have in person class instead of Map<String, Double> nameScoreTogether; a list of object like this: List<Information> nameScoreTogether and Information includes an attribute called String:name, and attribute called double:age

    The Person class changes as

    public class Person {
        int age;
        double lineScoreMax;
        List<Information> nameScoreTogether;
    
        Person(int age, double score) {
            this.age = age;
            this.lineScoreMax = score;
        }
    
        Person(int age, double score,  List<Information> nameScoreTogether) {
            this.age = age;
            this.lineScoreMax = score;
            this.nameScoreTogether = nameScoreTogether;
        }
        //Getters
    }
    

    Information class:

    private class Information {
        private String name;
        private double score;
    
       Information(String name, double score) {
            this.name = name;
            this.score = score;
        }
    }
    

    Use the below block in place of //Find the map of name to score in the earlier provided code.

    entry.getValue()
         .stream()
         .map(personNameEntry -> new Information(personNameEntry.getValue(),
                                personNameEntry.getKey().getLineScoreMax()))
         .collect(Collectors.toList())
    

    UPDATE 2:

    If Information class only has a single argument constructor and a setter for score, change the map step as

    .map(personNameEntry -> {
        Information information = new Information(personNameEntry.getValue());
        information.setScore(personNameEntry.getKey().getLineScoreMax());
        return information;
      })