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

时间:2016-02-08 15:35:51

标签: java dictionary grouping

我有一个像这样的简单对象

public class Person{

 private int id;
 private int age;
 private String hobby;

 //getters, setters

}

我想按属性

Person列表进行分组

输出应该是这样的

Person count/Age/Hobby
2/18/Basket
5/20/football

使用图表了解更多

chart

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

颜色代表年龄

我设法使用地图按一个属性分组,但我无法计算如何按多个属性进行分组

//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);
        }

然后我像这样检索可分组对象

  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 retieve the group by hobby here too... 
        }

任何建议都将不胜感激。 非常感谢你

3 个答案:

答案 0 :(得分:2)

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

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

        @Override
        public int compare(Person o1, Person o2) {
            return o1.age-o2.age;
        }
    };
}

然后,您只需致电:Arrays.sort(people,Person.getAgeComparator())或使用以下代码对Collection进行排序:

List<Person> people = new ArrayList<>();
people.sort(Person.getAgeComparator());

要同时使用多个Comparator进行排序,首先要为每个字段定义Comparator(例如,一个用于年龄,一个用于名称)。然后,您可以使用ComparatorChain将它们组合在一起。您可以使用ComparatorChain,如下所示:

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

答案 1 :(得分:2)

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

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);
}

使用personMapGrouped.get("18;Football").getSize()可以轻松确定条目数。

答案 2 :(得分:2)

我不确定您的要求,但我可能会使用多个地图(Google Guava&#39; Multimap会使bww更容易)并设置,例如像这样的东西:

//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

由于我使用值集Person需要equals()hashCode()的合理实施,这可能会使用id字段。这也有助于查询。

构建子集非常简单:

Set<Person> age18 = personsByAge.get(18);
Set<Person> basketballers = personsByHobby.get( "basketball" );

//making use of Guava again
Set<Person> basketballersAged18 = Sets.intersection( age18, basketballers );

请注意,我在此处使用了Google Guava,但您可以通过一些额外的手动代码实现相同的功能(例如,使用Map<String, Set<Person>>并手动创建值集以及使用Set.retainAll()方法)。

相关问题