根据另一个对象的集合对一个对象列表进行分组



我想根据另一个对象(Conditions)的列表对对象列表(Promotions)进行分组。


Condition.java
class Promotion {
String promoId;
String promoDesc;
String promoCode;
Criteria criteria;

public Promotion(String promoId, String promoDesc, String promoCode, Criteria criteria) {
super();
this.promoId = promoId;
this.promoDesc = promoDesc;
this.promoCode = promoCode;
this.criteria = criteria;
}
}

Criteria.java

class Criteria {
String name;
List<Condition> conditions;

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Condition> getConditions() {
return conditions;
}
public void setConditions(List<Condition> condition) {
this.conditions = condition;
}
}

and Condition.java

class Condition {
String attribute;
String operator;
String value;

public Condition(String attribute, String operator, String value) {
super();
this.attribute = attribute;
this.operator = operator;
this.value = value;
}
}

下面是GroupingTest.java

public class GroupingTest {
public static void (String[] args) {

Condition cond1 = new Condition("term", "equals", "24");
Condition cond2 = new Condition("term", "not equals", "12");

Condition cond3 = new Condition("handset", "equals", "ABC");
Condition cond4 = new Condition("handset", "equals", "XYZ");

// ABC handset with term 24
Criteria c1 = new Criteria();
c1.setName("ABCwith24");        
c1.setConditions(Arrays.asList(cond1,cond3));

// XYZ handset with term 12
Criteria c2 = new Criteria();
c2.setName("XYZwith12");        
c2.setConditions(Arrays.asList(cond2,cond4));

// ABC handset with term 24
Criteria c3 = new Criteria();
c3.setName("handset24");        
c3.setConditions(Arrays.asList(cond1,cond3));

// XYZ handset with term 12
Criteria c4 = new Criteria();
c4.setName("handset12");        
c4.setConditions(Arrays.asList(cond2,cond4));

// XYZ handset with term 12
Criteria c5 = new Criteria();
c5.setName("XYZ24");        
c5.setConditions(Arrays.asList(cond1,cond4));


// new Promotion( promoId,promoDesc, promoCode, criteria)
Promotion promo1 = new Promotion("P1", "Promo1", "ABC24", c1);
Promotion promo2 = new Promotion("P2", "Promo2", "XYZ12", c2);
Promotion promo3 = new Promotion("P3", "Promo3", "AAA24", c3);      
Promotion promo4 = new Promotion("P4", "Promo4", "BBB12", c4);
Promotion promo5 = new Promotion("P5", "Promo5", "CCC12", c5);

List<Promotion> promos = Arrays.asList(promo1,promo2,promo3,promo4,promo5);

//TODO grouping

}
而预期结果为:
Grp1 with promo1, promo3 (since conditions are matching though the criteria is different objects (c1, c3).
Grp2 with promo2, promo4 ( conditions  of c2, c4 are same)
Grp3 with promo5

是否有一种方法,我们可以做到这一点,使用collector . groupingby()在java8或任何解决方案?请注意,所有的对象是第三方供应商;所以不能访问代码库。

可以这样做:

Map<String, List<Promotion>> promotionsGroupedByConditions = promos.stream()
.collect(Collectors.groupingBy(promo -> {
// the order of conditions should not matter
promo.criteria.conditions.sort(comparator);
return promo.criteria.conditions.stream()
.map(condition -> condition.attribute + "/" + condition.operator + "/" + condition.value)
.collect(Collectors.joining(" & "));
}));

假设条件的顺序应该被忽略,所以你需要这个:

public final static Comparator<? super Condition> comparator = new Comparator<Condition>() {
@Override
public int compare(Condition o1, Condition o2) {
int attributeCompare = o1.attribute.compareTo(o2.attribute);
if (attributeCompare != 0)
return attributeCompare;
int operatorCompare = o1.operator.compareTo(o2.operator);
if (operatorCompare != 0)
return operatorCompare;
int valueCompare = o1.value.compareTo(o2.value);
return valueCompare;
}
};

并以可读形式打印:

promotionsGroupedByConditions.entrySet().stream().forEach(entry -> {
System.out.print(entry.getKey() + ": ");
entry.getValue().forEach(v -> System.out.print(v.promoId + " "));
System.out.println();
});

输出:

handset/equals/XYZ & term/not equals/12: P2 P4 
handset/equals/ABC & term/equals/24: P1 P3 
handset/equals/XYZ & term/equals/24: P5