2017-02-28 27 views
0

我有一个用户列表。Java:如何使用Stream API按条件对实体进行分组?

class User { 
    String name; 
} 

而且我需要按名称对用户进行分组。

List<Set<User>> groupedBy; 

的分组条件是名称相似,它的一些比较

Comparator<User> p = new Comparator<User>() { 
    // some comparison logic 
}; 

通过类似的名字,我组的用户如何使用Java 8流?

我试着使用partitioning,但它有一个不同的API比我更需要。

Map<Boolean, List<User>> collected = users.stream().collect(Collectors.partitioningBy(new Predicate<User>() { 
    @Override 
    public boolean test(User user) { 
     // ... 
    } 
}, Collectors.toList())); 
+0

你基于谓词试图'group'?听起来像'分区'。 – Eugene

+0

对不起,基于名称比较。 – Finkelson

+0

如果没有流API,你会怎么做?考虑到像莱文斯坦距离这样的事情,它不会导致一个明确分离的集合,因为它不是传递的。 –

回答

2

通常情况下,如果你通过一个简单的属性要组,你会使用

Map<String,Set<User>> m=users.stream() 
    .collect(Collectors.groupingBy(User::getName, Collectors.toSet())); 

但是,如果你有一个表示为一个已经存在的Comparator,例如一个复杂的逻辑

Comparator<User> comparator=Comparator.comparing(u -> u.getName(), Collator.getInstance()); 

可以根据封装在比较器逻辑使用

Map<User,Set<User>> m=users.stream().collect(
    Collectors.groupingBy(u -> u,() -> new TreeMap<>(comparator), Collectors.toSet())); 

到组。

在这两种情况下,你会得到一个Map可以转换到使用

List<Set<User>> groupedBy = new ArrayList<>(m.values()); 

你想要的清单还可以表示最后一步为Collector的一部分,例如

List<Set<User>> groupedBy=users.stream().collect(
    Collectors.collectingAndThen(
     Collectors.groupingBy(u -> u,() -> new TreeMap<>(comparator), Collectors.toSet()), 
     m -> new ArrayList<Set<User>>(m.values()))); 
+0

是...为什么不只是将比较器提供给接受一个的地图?一加 – Eugene

相关问题