Java 按多个字段对列表中的对象分组

Java 按多个字段对列表中的对象分组,java,dictionary,grouping,Java,Dictionary,Grouping,我有一个像这样的简单物体 public class Person { private int id; private int age; private String hobby; //getters, setters } Person count/Age/Hobby 2/18/Basket 5/20/football for (Map.Entry<String, List<Person>> entry : personMapGroupped .entry

我有一个像这样的简单物体

public class Person {
 private int id;
 private int age;
 private String hobby;

 //getters, setters
}
Person count/Age/Hobby
2/18/Basket
5/20/football
  for (Map.Entry<String, List<Person>> entry : personMapGroupped .entrySet()) {

            String key = entry.getKey();// group by age
            String value = entry.getValue(); // person count
            // I want to retrieve the group by hobby here too... 
        }
我想按属性对
人员的列表进行分组

//group only by age . I want to group by hobby too
 personMapGroupped = new LinkedHashMap<String, List<Person>>();
 for (Person person : listPerson) {
            String key = person.getAge();
            if (personMapGroupped.get(key) == null) {
                personMapGroupped.put(key, new ArrayList<Person>());
            }
            personMapGroupped.get(key).add(person);
        }
输出应该是这样的

public class Person {
 private int id;
 private int age;
 private String hobby;

 //getters, setters
}
Person count/Age/Hobby
2/18/Basket
5/20/football
  for (Map.Entry<String, List<Person>> entry : personMapGroupped .entrySet()) {

            String key = entry.getKey();// group by age
            String value = entry.getValue(); // person count
            // I want to retrieve the group by hobby here too... 
        }
用图表来加深理解

X轴:爱好重新分区 Y轴:人员分布计数

颜色代表年龄

我设法使用map按一个属性分组,但我不知道如何按多个属性分组

//group only by age . I want to group by hobby too
 personMapGroupped = new LinkedHashMap<String, List<Person>>();
 for (Person person : listPerson) {
            String key = person.getAge();
            if (personMapGroupped.get(key) == null) {
                personMapGroupped.put(key, new ArrayList<Person>());
            }
            personMapGroupped.get(key).add(person);
        }
//仅按年龄分组。我也想按爱好分组
personMapGroupped=新建LinkedHashMap();
for(个人:listPerson){
String key=person.getAge();
if(personMapGroupped.get(key)==null){
put(key,newarraylist());
}
personMapGroupped.get(key).add(person);
}
然后像这样检索可分组对象

public class Person {
 private int id;
 private int age;
 private String hobby;

 //getters, setters
}
Person count/Age/Hobby
2/18/Basket
5/20/football
  for (Map.Entry<String, List<Person>> entry : personMapGroupped .entrySet()) {

            String key = entry.getKey();// group by age
            String value = entry.getValue(); // person count
            // I want to retrieve the group by hobby here too... 
        }
for(Map.Entry:personMapGroupped.entrySet()){
String key=entry.getKey();//按年龄分组
String value=entry.getValue();//人数
//我也想在这里通过爱好来找回这个团体。。。
}
如有任何建议,将不胜感激


非常感谢

根据不同领域实施人员比较方法。例如,如果要按年龄分组,请将此方法添加到
Person

public static Comparator<Person> getAgeComparator(){
    return new Comparator<Person>() {

        @Override
        public int compare(Person o1, Person o2) {
            return o1.age-o2.age;
        }
    };
}
List<Person> people = new ArrayList<>();
people.sort(Person.getAgeComparator());
要同时使用多个
比较器进行排序
,首先为每个字段定义一个
比较器
(例如,一个用于年龄,一个用于姓名)。然后,您可以使用一个组合键将它们组合在一起。您可以按如下方式使用
ComparatorChain

ComparatorChain chain = new ComparatorChain();
chain.addComparator(Person.getNameComparator());
chain.addComparator(Person.getAgeComparator());

您可以简单地将属性组合到一个键

for (Person person : listPerson) {
    String key = person.getAge() + ";" + person.getHobby();
    if (!personMapGrouped.contains(key)) {
       personMapGrouped.put(key, new ArrayList<Person>());
    }
    personMapGrouped.get(key).add(person);
}
for(个人:listPerson){
字符串键=person.getAge()+“;”+person.getHobby();
如果(!personMapGrouped.contains(键)){
put(key,newarraylist());
}
personMapGrouped.get(key).add(person);
}

通过使用
personMapGrouped.get(“18;Football”).getSize()
我不确定您的要求,但我可能会使用多个地图(Google Guava的
Multimap
会让这更容易)和设置,例如:

//I'm using a HashMultimap since order of persons doesn't seem to be relevant and I want to prevent duplicates   
Multimap<Integer, Person> personsByAge = HashMultimap.create();

//I'm using the hobby name here for simplicity, it's probably better to use some enum or Hobby object
Multimap<String, Person> personsByHobby = HashMultimap.create();

//fill the maps here by looping over the persons and adding them (no need to create the value sets manually

请注意,我在这里使用了Google Guava,但您可以通过一些额外的手动代码(例如,使用
Map
和手动创建值集以及使用
Set.retainal()
方法)实现相同的功能。

实现可比较的界面,然后对列表排序分组应该如何工作?是否应按单个属性(即每个属性一张地图)、属性组合(即组合地图键)或属性层次(例如先按年龄,然后按爱好)对人员进行分组?@Thomas非常感谢。组合将非常好(例如:PersonCount/Age/Hobby,因为稍后我需要将它们放入for循环中。我编辑了我的答案。不幸的是,您的编辑没有让它更清晰。您是否希望按年龄获得人数,然后按爱好分组,例如“所有18岁的人,所有喜欢打篮球的人”?或者你想让所有人的爱好独立于他们的年龄吗?你需要用Java做这件事有什么原因吗?这是一件你可能会发现使用数据库容易得多的事情。谢谢,我不知道这个Google Guava库,它方便了很多事情。但是我仍然很难在我的案例中使用它。我更新了它带一张代表所需输出的图表。请look@ulquiorra这应该不太难实现。只要根据需要将数据分成单独的子集(即爱好和年龄),并获得这些子集的交点大小作为条形图的数据。毕竟,您仍然需要6个单独的值。