Java 分组元素,每个组仅包含一个具有指定字段的对象
我对java对象进行分组有问题。让我们看看示例对象:Java 分组元素,每个组仅包含一个具有指定字段的对象,java,java-stream,groupingby,Java,Java Stream,Groupingby,我对java对象进行分组有问题。让我们看看示例对象: public class MyObject { private String field1; public MyObject(String field1) { this.field1 = field1; } } 我想要实现的是将MyObject分组,这样每个组只包含一个具有指定field1值的对象。例如,对于此类元素列表: public static void main(String[] ar
public class MyObject {
private String field1;
public MyObject(String field1) {
this.field1 = field1;
}
}
我想要实现的是将MyObject
分组,这样每个组只包含一个具有指定field1
值的对象。例如,对于此类元素列表:
public static void main(String[] args) {
MyObject o1 = new MyObject("1");
MyObject o2 = new MyObject("1");
MyObject o3 = new MyObject("1");
MyObject o4 = new MyObject("2");
MyObject o5 = new MyObject("2");
MyObject o6 = new MyObject("3");
List<MyObject> list = Arrays.asList(o1, o2, o3, o4, o5, o6);
List<List<MyObject>> listsWithUniqueField1Values = new ArrayList<>();
我曾尝试使用
java.util.stream.Collectors.groupingBy
方法以有效的方式实现它,但失败了。我认为使用groupingBy无法实现。这是我的解决方案——我还添加了一个自动生成的equals、hashCode和toString
public class SO67140234 {
public static void main(String[] args) {
MyObject o1 = new MyObject("1");
MyObject o2 = new MyObject("1");
MyObject o3 = new MyObject("1");
MyObject o4 = new MyObject("2");
MyObject o5 = new MyObject("2");
MyObject o6 = new MyObject("3");
List<MyObject> list = Arrays.asList(o1, o2, o3, o4, o5, o6);
List<Set<MyObject>> listsWithUniqueField1Values = new ArrayList<>();
outer:
for (MyObject obj : list) {
for (Set<MyObject> bucket : listsWithUniqueField1Values) {
if (bucket.add(obj)) {
continue outer;
}
}
listsWithUniqueField1Values.add(new HashSet<>(Collections.singleton(obj)));
}
System.out.println(listsWithUniqueField1Values);
}
}
class MyObject {
private final String field1;
public MyObject(String field1) {
this.field1 = field1;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyObject myObject = (MyObject) o;
return Objects.equals(field1, myObject.field1);
}
@Override
public int hashCode() {
return Objects.hash(field1);
}
@Override
public String toString() {
return "MyObject{" +
"field1='" + field1 + '\'' +
'}';
}
}
公共类SO67140234{
公共静态void main(字符串[]args){
MyObject o1=新的MyObject(“1”);
MyObject o2=新的MyObject(“1”);
MyObject o3=新的MyObject(“1”);
MyObject o4=新的MyObject(“2”);
MyObject o5=新的MyObject(“2”);
MyObject o6=新的MyObject(“3”);
列表=数组.asList(o1,o2,o3,o4,o5,o6);
List listsWithUniqueField1Values=new ArrayList();
外部:
对于(MyObject对象:列表){
for(设置存储桶:ListSwithUniqueField1值){
如果(桶添加(obj)){
继续对外开放;
}
}
添加(新的HashSet(Collections.singleton(obj));
}
System.out.println(ListSwithUniqueField1值);
}
}
类MyObject{
私有最终字符串字段1;
公共MyObject(字符串字段1){
此字段1=字段1;
}
@凌驾
公共布尔等于(对象o){
如果(this==o)返回true;
如果(o==null | | getClass()!=o.getClass())返回false;
MyObject MyObject=(MyObject)o;
返回Objects.equals(field1,myObject.field1);
}
@凌驾
公共int hashCode(){
返回Objects.hash(field1);
}
@凌驾
公共字符串toString(){
返回“MyObject{”+
“field1=”+field1+“\”+
'}';
}
}
为了按MyObject
的实例进行分组,此类需要实现equals
和hashCode
方法,并且field1
应该是最终的,以避免hashCode
在更改其值时损坏
公共类MyObject{
私有最终字符串字段1;
公共MyObject(字符串字段1){
此字段1=字段1;
}
公共字符串getField1(){返回this.field1;}
@凌驾
公共布尔等于(对象o){
如果(this==o)返回true;
if(null==o | |!(o MyObject的instanceof))返回false;
MyObject that=(MyObject)o;
返回Objects.equals(this.field1,that.field1);
}
@凌驾
公共int hashCode(){
返回Objects.hash(this.field1);
}
@凌驾
公共字符串toString(){
return“field1=”+this.field1;
}
}
收集器。groupingBy
不能用于获得所需的结果,但可以应用自定义操作来创建一组唯一的MyObject
实例(在某种程度上提醒@Rubydesic的解决方案,但没有嵌套循环)
List List=Arrays.asList(o1、o4、o5、o2、o6、o3);
列表结果=List.stream()
.收集(
ArrayList::新建,//`供应商`
(lst,x)->{//累加器
对于(集合:lst){
如果(设置添加(x)){
return;//找到一个bucket来放置MyObject实例
}
}
//创建新桶
Set newSet=newhashset();
新闻集添加(x);
第一次添加(新闻集);
},
(lst1,lst2)->{}//空组合器
);
系统输出打印项次(结果);
输出:
[[field1=1, field1=2, field1=3], [field1=1, field1=2], [field1=1]]
您可以使用
groupingBy
本身来实现这一点。(不需要等于
或哈希代码
)
field1
。这将给出一张地图,如下所示:MyObject
添加到listsWithUniqueField1Values
中的不同列表中1
,列表变成[[1]]
->[[1],[1]]
->[[1],[1],[1]]
b。然后按2
,列表变成[[1,2],[1],[1]]
->[[1,2],[1,2],[1]]
c。对于键3
,列表变为[[1,2,3],[1,2],[1]]
代码:
List uniqueList=newarraylist();
list.stream()
.collect(收集器.groupingBy(MyObject::getField1))
.values()
.stream()
.forEach(值->添加列表(唯一列表,值));
返回唯一列表;
下面的方法addToList
用于填充唯一列表。
在这种情况下,ListIterator
用于Iterator
,因为add
方法在ListIterator
中可用
private static void addToList(列表唯一列表,列表值){
ListIterator迭代器=uniqueList.ListIterator();
对于(MyObject o:值){
名单;
如果(!iterator.hasNext()){
//需要将对象添加到新列表中。
列表=新的ArrayList();
迭代器。添加(列表);
}否则{
list=iterator.next();
}
列表。添加(o);
}
}
假设MyObject
有一个getter,我能想到的最简单的方法之一就是组合
- 收藏,收藏,然后
- 收集者分组
- 链接列表
- 从LinkedList弹出项目并将其插入结果中的方法
List finalResult=List.stream()
收集,收集收集,然后收集(
Collectors.groupingBy(MyObject::getField1,Collectors.toCollection(LinkedList::new)),
地图->{
[[field1=1, field1=2, field1=3], [field1=1, field1=2], [field1=1]]
{ 1 : [1,1,1], 2 : [2,2], 3 : [3] }