如何在一次迭代中按两个属性对对象列表进行分组?

时间:2016-11-24 15:13:57

标签: java

我试图按两个属性对一大组对象进行分组。为了证明我的意思,请考虑以下示例。

public class Foo {

    private String attributeA;
    private String attributeB;
    private String anotherAttribute;
}

我想按属性FooattributeAattributeB个对象进行分组。目前我做了以下事情。

List<Foo> foos = getFoos();
Map<Set<String>, List<String>> groupedFoos = Sets.newHashMap();
Set<String> fooGroup;
for(Foo foo : foos) {
    fooGroup = Sets.newHashMap(foo.getAttributeA(), foo.getAttributeB());

    if (!groupedFoos.containsKey(fooGroup)) {
        groupedFoos.put(fooGroup, Lists.newArrayList(foo));
    } else {
        groupedFoos.get(fooGroup).add(foo);
    }
}

如果不使用像Map这样的Map<Set<String>, List<String>>,我怎样才能获得相同的结果?在一次迭代中执行此操作非常重要。可以交换属性attributeAattributeB的值。因此,使用Pair作为Map的关键字也不是一种选择。

2 个答案:

答案 0 :(得分:3)

如果你想摆脱Map作为关键,你总是可以用比较两种属性的方式编写自己的Key(无论其顺序如何)。

public class Key {
    private String a;
    private String b;
    private String c;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Key foo = (Key) o;

        if (a.equals(foo.a) || a.equals(foo.b)) {
            return true;
        }

        return b.equals(foo.b) || b.equals(foo.a);
    }

    @Override
    public int hashCode() {
        int result = a.hashCode();
        result = 31 * result + b.hashCode();
        return result;
    }
}

答案 1 :(得分:1)

为您的班级添加关键方法。

public class Foo {

    private String attributeA;
    private String attributeB;
    private String anotherAttribute;

    public final String getKey() {
      return this.attributeA + "$" + this.attributeB; //use $ or any other delimiter as suggested in the comment
    }
}

然后,如果您可以使用Java8,请使用下面的Collectors.groupingBy()方法

 final Map<String, List<Foo>> result = getFoos().stream().collect(Collectors.groupingBy(Foo:getKey));