Java:如何使用不同的 equals 定义执行列表操作?

发布于 2024-08-13 05:29:34 字数 753 浏览 4 评论 0原文

Java:如何使用不同的 equals 定义执行列表操作?

我有两个通用 POJO 列表。我需要根据比较列表中 POJO 的不同方式对列表执行一些集合操作。

例如,如果我的 POJO 具有以下结构:(

public class GenericPojo {
    private String id;
    private String address;
    private String city;
    private String country;
    private String extraDetails;
}

具有适当的 getter 和 setter)

给定 List1List2,我将如何找到:

List1 - List2(如果只是 ID 相等,则 GenericPojo 类相等)

List1 和 List2 的交集(其中 idaddresscitycountry,但 GenericPojoextraDetails 不相等)

两个不同的自定义比较器类在这里会有帮助吗?是否有任何库可以有效地处理这些操作,或者我应该尝试实现自己的库?

Java: How do I perform list operations with different definitions of equals?

I have two lists of generic POJOs. I need to perform some set operations on the lists based on different ways of comparing the POJOs within the lists.

For example, if my POJO had the following structure:

public class GenericPojo {
    private String id;
    private String address;
    private String city;
    private String country;
    private String extraDetails;
}

(with the appropriate getters and setters)

Given List1<GenericPojo> and List2<GenericPojo>, how would I find:

List1 - List2 (where the GenericPojo classes are equal if just the IDs are equal)

Intersect of List1 and List2 (where id, address, city, country, but not extraDetails of GenericPojo are equal)

Would two different custom comparator classes be helpful here? Are there any libraries that handle these operations effectively or should I try implementing my own?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

白衬杉格子梦 2024-08-20 05:29:34

如果您必须操纵超出您控制范围的类,我建议使用委托。这是我的尝试:

  1. 基于 装饰器模式
  2. 使用单个方法“public boolean equal(T t1, T, t2)”创建一个 EqualityChecker 接口。
  3. 为您的通用 pojo 实现此接口两次:一次仅检查 ID,另一次检查其他字段。
  4. 添加您感兴趣的两种方法(集合减法和集合交集),但带有一个补充参数,该参数是 EqualityChecker 具体实例,它将为您执行相等测试。

因此,您可以将这两个操作添加到您已为其编写 EqualityChecker 的任何类型对象的所有现有 List 中。

进一步改进:您还可以编写一个默认 EqualityChecker,它只调用比较对象的 equals 方法。然后,您可以重载这两个新操作以默认 EqualityChecker

If you must manipulate class out of your control, I would suggest using delegation. Here is my try:

  1. Create a RichList<T> wrapper around Lists implementing the List contract, based on the decorator pattern.
  2. Create an EqualityChecker<T> inteface, with a single method `public boolean equal( T t1, T, t2).
  3. Implement this interface for your generic pojo twice: one checking just the ID and the other checking the other fields.
  4. Add both methods you are interested in (set substraction and set intersection), but with a supplementary argument which is the EqualityChecker<T> concrete instance that will do the equality test for you.

So you can add both operations to all existing Lists for any kind of object for which you have written an EqualityChecker.

Further improvements: You can also write a default EqualityChecker<T> which just calls the equals method of the compared objects. You can then overload both new operations to default the EqualityChecker.

可遇━不可求 2024-08-20 05:29:34

如果您的列表不包含重复项(相对于假设的自定义比较器类),您可以使用两个 TreeSet,分别用两个比较器实例化。

这样做的一个缺点(除了重复约束之外)是迭代元素时获得的顺序取决于比较器。

If your lists contain no duplicates (with repsect to the hypothetical custom comparator classes) you can use two TreeSets instead, instantiated with your two comparators respectively.

A drawback of this (apart from the duplication constraint) is that the order you get when iterating over elements depend on the comparators.

全部不再 2024-08-20 05:29:34

鉴于您对平等的具体要求, List#removeAll()List#retainAll() 不符合您的需求,所以我认为您需要一个自定义实现来执行与这两个操作类似的操作。

Given your specific requirements on equality, List#removeAll() and List#retainAll() won't fit your needs so I think you'll need a custom implementation to do something similar to both operations.

画尸师 2024-08-20 05:29:34

没有遵循 List 契约的解决方案,并且现有的 list 实现都不允许您提供比较器。 List 合约根据每个元素的 equals(Object) 方法定义列表的行为。

如果比较器的 compare 方法与每个元素的 equals(Object) 方法不一致,那么使用具有不同比较器的 TreeSet 的建议也违反了约定。

在实践中,您可能需要实现自己的列表类。您可以将其设为不严格遵循 List 约定的 List 实现,但您需要小心,这不会破坏其他库方法/类。

There is no solution that obeys the List contract, and none of the existing implementations of list allow you to supply a comparator. The List contract defines the behavior of the list in terms of each element's equals(Object) method.

The suggestion of using TreeSets with different comparators is also a violation of the contract if the comparator's compare method is inconsistent with each element's equals(Object) method.

In practice you may need to implement your own list classes. You could make it a List implementation that doesn't strictly follow the List contract, but you need to be careful that this doesn't break other library methods / classes.

拥抱影子 2024-08-20 05:29:34

如果您不想自己编写集合操作并且您不介意浪费一些 CPU 和内存资源,您可以:

  • 根据您的 WrappedPojo 构造>GenericPojo
  • WrappedPojo 提供了 equals() 的合适实现,
  • 创建适当类型的 WrappedPojo 的新列表来执行操作 操作完成后,将
  • 包含的 GenericPojo 复制回其原始容器(如果需要)。

丑陋但简单。

If you don't want to program the set operations yourself and you don't mind wasting some CPU and memory resources, you could:

  • construct WrappedPojos based on your GenericPojos
  • give the WrappedPojo suitable implementations of equals()
  • create new lists of the appropriate kind of WrappedPojo to do the operation on
  • copy the contained GenericPojos back to their original containers (if needed) after the operation's finished.

Ugly but simple.

樱花坊 2024-08-20 05:29:34

您可以通过以下方法将所有这些保留在域对象中:

  1. 仅基于 GenericPojo 上实现 equals(...) >id。
  2. 使用基于附加 equals(...)WrappedPojo 定义为 GenericPojo 的包装器GenericPojo 字段。
  3. 对于第二个用例,使用包装实例的列表。

我认为根本问题是试图拥有一个具有不同平等定义的单一域类。

You could keep all of this in the domain objects by the following approach:

  1. Implement equals(...) on GenericPojo based only on id.
  2. Define WrappedPojo as a wrapper around GenericPojo with an equals(...) based on the additional GenericPojo fields.
  3. For the second use case, use a list of wrapped instances.

I suggest that the root issue is trying to have a single domain class with different definitions of equality.

烟花易冷人易散 2024-08-20 05:29:34

您尝试执行的两个操作都是函数式的,尽管 Java 不能很好地支持这些操作,并且您可能会以非常不同的方式编写它们。
您可能必须重新考虑您想要实现的目标以适合 java。

您正在做的是对数据类型的投影(即字段的子集)执行操作。

您使用的操作也是 Set 操作,而不是 List 操作。例如,您不能获取两个列表的交集(或者至少您必须定义这意味着什么),“删除”可能也不会完全按照您对列表的预期执行。

想象一下,您有一个方法,它返回仅包含您指定的字段的 pojo 集合。我过去写过一个库,可以通过动态生成的类来有效地完成此操作,请查看函数式 Java 或类似的库。

public static <Pojo, Pojo2> Set<Pojo2> project(Collection<Pojo> collection,
      String... fieldsToRetain);

List1 - List2(如果只是 ID 相等,则 GenericPojo 类相等)

Set<PojoWithId> setOfIds = project(list1, "id")
setOfIds.retainAll(project(list2, "id"));

List1 和 List2 的交集(其中 id、地址、城市、国家/地区,但 GenericPojo 的 extraDetails 不相等)

Set<PojoWithThreeFields> intersection = project(list1, "id", "address", "city", "country");
intersection.retainAll(project(list2, "id", "address", "city", "country"));

Both operations you are trying to perform are functional, though Java doesn't support these very well and you are likely to be writing them in a very different way.
You may have to rethink what it is you are trying to achieve to suit java.

What you are doing is performing an operation on a projection of the data type (i.e. for a sub set of fields)

The operations you are using are also Set operations, rather than List operations. e.g. you cannot take an intersection of two lists (or at least you have to define what that means) Remove may not perform exactly as you expect for list as well.

Imagine you have a method which returns a collection of pojos with just the fields you specify. I have written a library to do this efficiently with dynamicly generated class in the past, have a look at functional Java or similar.

public static <Pojo, Pojo2> Set<Pojo2> project(Collection<Pojo> collection,
      String... fieldsToRetain);

List1 - List2 (where the GenericPojo classes are equal if just the IDs are equal)

Set<PojoWithId> setOfIds = project(list1, "id")
setOfIds.retainAll(project(list2, "id"));

Intersect of List1 and List2 (where id, address, city, country, but not extraDetails of GenericPojo are equal)

Set<PojoWithThreeFields> intersection = project(list1, "id", "address", "city", "country");
intersection.retainAll(project(list2, "id", "address", "city", "country"));
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文