繁体   English   中英

如果对象上的属性相同,则压缩对象列表

[英]Condense a list of objects if a property on the object is the same

我有一个对象列表,如下所示:

public class MyObject {

  String id;
  List<String> list;

  MyObject(String id, List<String> list) {
    this.id = id;
    this.list = list;
  }

  String getId() {
    return id;
  }

  List<String> getList() {
    return list;
  }
}

我想压缩列表,以便如果两个MyObject具有相同的id,它们将合并为一个。

我能想到的最好的解决方案是覆盖MyObject中的equals方法,这样如果它们的id相同,则2个对象是相同的,并执行如下操作:

List<MyObject> condense(List<MyObject> fullList) {
  List<MyObject> condensedList = new ArrayList<>();
  for (MyObject obj : fullList) {
    if (condensedList.contains(obj)) {
      MyObject obj2 = condensed.get(condensed.indexOf(obj));
      obj = merge(obj, obj2);
    }
    condensedList.add(obj);
  }
  return condensedList;
}

MyObject merge(MyObject obj1, MyObject obj2) {
  List<String> merged = new ArrayList<>();
  merged.addAll(obj1.getList());
  merged.addAll(obj2.getList());
  return new MyObject(obj1.getId(), merged);
}

这不是一个很好的解决方案,因为如果它们的ID是相同的那些对象并不是真的相等,它们只需要在这种特殊情况下组合。 而且它不是很简洁。 有没有更好的办法?

你确实可以使这更简洁。

List<MyObject> condense(List<MyObject> fullList) {
      Map<String, MyObject> tempMap = new HashMap<>();
      fullList.forEach(a -> tempMap.merge(a.getId(), a, MyObject::merge));
      return new ArrayList<>(tempMap.values());
}

这使用Map :: merge来执行工作。 Map :: merge基本上表示如果指定的键a.getId()尚未与值关联或与null关联,则将其与给定的非null值相关联。

否则,将相关值替换为给定重映射函数MyObject::merge的结果,或者如果结果为null则删除。

完成后,我们收集映射值并将其返回到ArrayList实例中。

注意上面的MyObject::merge函数假定mergeMyObject类中定义为public static MyObject merge (MyObject obj1, MyObject obj2) {...}

对集合对象使用Map

public static List<MyObject> condense(List<MyObject> objs) {
    objs = Optional.ofNullable(objs).orElse(Collections.emptyList());

    Map<String, MyObject> map = new LinkedHashMap<>();   
    objs.stream().map(MyObject::getId).distinct().forEach(id -> map.put(id, new MyObject(id)));  
    objs.forEach(obj -> map.get(obj.getId()).addList(obj.getList()));

    return new ArrayList<>(map.values());
}

PS注意MyObject封装:

public final class MyObject {

    private final String id;
    private final List<String> list = new ArrayList<>();

    public MyObject(String id) {
        this.id = id;
    }

    public String getId() {
        return id;
    }

    public List<String> getList() {
        return list.isEmpty() ? Collections.emptyList() : Collections.unmodifiableList(list);
    }

    public void addList(List<String> list) {
        this.list.addAll(list);
    }
}

您可以这样做,而不依赖于equals方法。

List<MyObject> condense(List<MyObject> fullList) {
    // LinkedHashMap preserves the order of the original list
    // To make the result sorted by ID, use TreeMap instead
    Map<String, List<String>> lists = new LinkedHashMap<>();

    for (MyObject o : fullList) {
        List<String> list = lists.get(o.getId());
        if (list == null) {
            list = new ArrayList<>(o.getList());
            lists.put(o.getId(), list);
        } else {
            list.addAll(o.getList());
        }
    }

    List<MyObject> objects = new ArrayList<>(lists.size());
    for (Map.Entry<String, List<String>> e : lists.entrySet()) {
        objects.add(new MyObject(e.getKey(), e.getValue()));
    }
    return objects;
}

我们可以使用Map的merge()方法:

List<MyObject> condense(List<MyObject> fullList) {
    Map<String, MyObject> map = new LinkedHashMap<>();
    fullList.forEach(myObject -> {
        map.merge(myObject.getId(), myObject, (myObject1, myObject2) -> {
            myObject1.getList().addAll(myObject2.getList());
            return myObject1;
        });
    });
    return new ArrayList(map.values());
}

注意:省略了null检查。

你的merge方法很好,虽然我会用一个大小来初始化它,以防止不必要的ArrayList调整大小。

static MyObject merge (MyObject obj1, MyObject obj2) {
    List<String> list1 = obj1.getList();
    List<String> list2 = obj2.getList();
    List<String> merged = new ArrayList<>(list1.size() + list2.size());
    merged.addAll(list1);
    merged.addAll(list2);
    return new MyObject(obj1.getId(), merged);
}

接下来,将List流式传输到Map这样您就可以使用合并函数来决定遇到相等键(您的id )时要执行的操作。 这比搜索列表中的匹配键更有效。

public List<MyObject> condense(List<MyObject> fullList) {
    Map<String, MyObject> temp = fullList.stream()
            .collect(Collectors.toMap(MyObject::getId, Function.identity(), Main::merge));
    return new ArrayList<>(temp.values());
}

在这里,您将使用Collectors.toMap的重载,该重载采用键映射器,值映射器和合并函数 我假设merge的类是Main 然后,您可以将值转换回List

Jackson (Java):反序列化相同的属性名但返回不同的对象。 其中一个返回 object 和第二个列表<object><div id="text_translate"><p>我有一个这样的 POJO:</p><pre> public class NewClass { String name; @JsonProperty("productType") ProductType productType2005; List&lt;ProductType&gt; productType; }</pre><p> 我想将 json 反序列化为 Pojo。 问题是我的属性名称相同 productType 但我可以期待两种不同的返回类型或数据结构。</p><ol><li> 返回ProductType</li><li> return List&lt;ProductType&gt;因为属性名称相同我如何有效地使用 Jackson 注释来解决它?</li></ol><p> 我使用 rest-assured 进行反序列化,使用 Lombok 进行典型的 getter 和 setter。</p></div></object>

[英]Jackson (Java) : deserialization for the same property name but return different objects. for one it return object and second List<Object>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 什么是基于对象值将对象列表压缩为的有效方法? 哈希图 <Key,List<Object> &gt;来自包含相同属性的对象列表 Jackson (Java):反序列化相同的属性名但返回不同的对象。 其中一个返回 object 和第二个列表<object><div id="text_translate"><p>我有一个这样的 POJO:</p><pre> public class NewClass { String name; @JsonProperty("productType") ProductType productType2005; List&lt;ProductType&gt; productType; }</pre><p> 我想将 json 反序列化为 Pojo。 问题是我的属性名称相同 productType 但我可以期待两种不同的返回类型或数据结构。</p><ol><li> 返回ProductType</li><li> return List&lt;ProductType&gt;因为属性名称相同我如何有效地使用 Jackson 注释来解决它?</li></ol><p> 我使用 rest-assured 进行反序列化,使用 Lombok 进行典型的 getter 和 setter。</p></div></object> 如何有效地将 object AD 列表转换为 object BVo 列表? 两个对象具有相同的属性值 如何从List对象中的新对象中设置属性值,并获得使用Java 8设置属性的相同对象的新List? 如何使用 Java 中的 object 属性对列表中的对象进行分组 在对象上设置属性会重置ArrayList中类似对象的相同属性 如何从 ArrayList 获取具有相同对象属性的对象列表 使用多个对象的列表对同一对象进程进行线程化 Java中同一对象内的对象列表
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM