[英]Grouping a list of objects into a list of lists by a boolean function using Java 8 streams
Say I have a list of objects.假设我有一个对象列表。 I want to group them into a list of lists where each inner list contains elements for which a boolean comparison function returns
true
:我想将它们分组到一个列表列表中,其中每个内部列表都包含布尔比较函数为其返回
true
元素:
public class VO {
public VO(int age, int val) {
this.age = age;
this.val = val;
}
public int age;
public int val;
}
public void testGrouping() {
// Equal to vo2
VO vo1 = new VO(1, 100);
// Equal to vo1 and vo3
VO vo2 = new VO(3, 105);
// Equal to vo2 but not vo1 (age difference > 2),
// so it belongs into a new bucket
VO vo3 = new VO(5, 110);
// Equal to vo3, so it belongs into the same bucket as vo3
VO vo4 = new VO(7, 116);
List<VO> values = Arrays.asList(vo1, vo2, vo3, vo4);
//Group values using isEqual(VO, VO) into buckets somehow
//Any two values in a bucket must pass the check
//Expected without any specific order:
//[[vo1, vo2, [vo3, vo4]]
}
private boolean isEqual(VO a, VO b) {
return Math.abs(a.age - b.age) <= 2 && Math.abs(a.val - b.val) <= 10;
}
This is just a simplified example of the data that I have, in reality the comparison method is more complicated than that.这只是我拥有的数据的一个简化示例,实际上比较方法比这更复杂。 Important is that each object must match each other object in its bucket regarding the check.
重要的是,每个对象必须在其存储桶中与检查相关的其他对象匹配。 The objects cannot be grouped/mapped by a specific value.
不能按特定值对对象进行分组/映射。
I already have code which does this but takes three levels of for-loops and which took me about a day to write.我已经有了执行此操作的代码,但需要三个级别的 for 循环,并且花了我大约一天的时间来编写。 I'm curious if this can be achieved easier with streams.
我很好奇这是否可以通过流更容易地实现。
Try mapping your items first, then use Collectors.groupingBy()
:首先尝试映射您的项目,然后使用
Collectors.groupingBy()
:
values.stream().map(name -> name.split("\\s+")).collect(groupingBy(a -> a[1]));
This does not return lists but arrays - but the concept is the same.这不会返回列表而是数组 - 但概念是相同的。
You can modify a bit the isEqual
method so that you can use it as a comparator for the TreeMap
.您可以稍微修改
isEqual
方法,以便将其用作TreeMap
的比较器。 Then you can collect the TreeMap<VO, List<VO>>
as follows.然后你可以收集
TreeMap<VO, List<VO>>
如下。 This code works in Java 7 :此代码适用于Java 7 :
public static int isEqual(VO a, VO b) {
if (Math.abs(a.age - b.age) > 2 || Math.abs(a.val - b.val) > 10)
return 1;
else if (Math.abs(a.age - b.age) <= 2 && Math.abs(a.val - b.val) <= 10)
return 0;
else
return -1;
}
public static void main(String[] args) {
VO vo1 = new VO(1, 100);
VO vo2 = new VO(3, 105);
VO vo3 = new VO(5, 110);
VO vo4 = new VO(7, 116);
List<VO> values = Arrays.asList(vo1, vo2, vo3, vo4);
Map<VO, List<VO>> buckets = new TreeMap<>(new Comparator<VO>() {
@Override
public int compare(VO o1, VO o2) {
return isEqual(o1, o2);
}
});
for (VO vo : values) {
List<VO> list = buckets.get(vo);
if (list == null) {
list = new ArrayList<>();
}
list.add(vo);
buckets.put(vo, list);
}
// output
System.out.println(buckets);
//{VO{1=100}=[VO{1=100}, VO{3=105}], VO{5=110}=[VO{5=110}, VO{7=116}]}
}
public static class VO {
public int age, val;
public VO(int age, int val) {
this.age = age;
this.val = val;
}
@Override
public String toString() {
return "VO{" + age + "=" + val + "}";
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.