treeset 删除重复数据java_java-TreeSet比较器在某些情况下无法删除重复...

您在询问:

如何固定比较器,使其始终根据ID删除重复项,并根据值(升序)然后ID(降序)对有序集进行排序?

您想要比较器

>根据Obj.id删除重复项

>按Obj.alue和Obj.id对集合进行排序

要求1)导致

Function byId = o -> o.id;

Set setById = new TreeSet<>(Comparator.comparing(byId));

要求2)导致

Function byValue = o -> o.value;

Comparator sortingComparator = Comparator.comparing(byValue).thenComparing(Comparator.comparing(byId).reversed());

Set setByValueAndId = new TreeSet<>(sortingComparator);

让我们看一下TreeSet的JavaDoc.它说:

Note that the ordering maintained by a set […] must be consistent with equals if it is to

correctly implement the Set interface. This is so

because the Set interface is defined in terms of the equals operation,

but a TreeSet instance performs all element comparisons using its

compareTo (or compare) method, so two elements that are deemed equal

by this method are, from the standpoint of the set, equal.

该集合将根据比较器进行排序,但还使用比较器比较其元素是否相等.

据我所知,无法定义同时满足这两个要求的比较器.由于TreeSet首先位于Set要求1)中,因此必须匹配.为了达到要求2),您可以创建另一个TreeSet:

Set setByValueAndId = new TreeSet<>(sortingComparator);

setByValueAndId.addAll(setById);

或者,如果您不需要集合本身,而是以所需顺序处理元素,则可以使用Stream:

Consumer consumer = ;

setById.stream().sorted(sortingComparator).forEach(consumer);

顺便说一句:

尽管可以根据给定的Comparator对Stream的元素进行排序,但没有一种采用Comparator来根据其删除重复项的独特方法.

编辑:

您有两个不同的任务:1.重复删除,2.排序.一个比较器不能解决两个任务.那有什么选择呢?

您可以在Obj上覆盖equals和hashCode.然后,可以使用HashSet或Stream删除重复项.

对于排序,您仍然需要比较器(如上所示).根据可比较JavaDoc,仅将可比较对象用于排序将导致排序不等于等式.

由于Stream可以解决这两个任务,因此这是我的选择.首先,我们覆盖hashCode并等于ID以标识重复项:

public int hashCode() {

return Integer.hashCode(id);

}

@Override

public boolean equals(Object obj) {

if (this == obj)

return true;

if (obj == null)

return false;

if (getClass() != obj.getClass())

return false;

Obj other = (Obj) obj;

if (id != other.id)

return false;

return true;

}

现在我们可以使用流:

// instantiating one additional Obj and reusing those from the question

Obj obj3a = new Obj(3, "a");

// reusing sortingComparator from the code above

Set set = Stream.of(obja, objb, objc, objd, obj3a)

.distinct()

.sorted(sortingComparator)

.collect(Collectors.toCollection(LinkedHashSet::new));

System.out.println(set); // [(3a), (1a), (2c)]

返回的LinkedHashSet具有Set的语义,但它也保留sortingComparator的顺序.

编辑(回答评论中的问题)

问:为什么它不能正确完成工作?

自己看看.如下更改您的比较器的最后一行

int r = result == 0 ? Integer.compare(a.id, b.id) : result;

System.out.println(String.format("a: %s / b: %s / result: %s -> %s", a.id, b.id, result, r));

return r;

运行一次代码,然后切换Integer.compare的操作数.开关导致不同的比较路径.区别在于何时比较(2a)和(1a).

在第一轮中(2a)大于(1a),因此将其与下一个条目(2c)进行比较.这导致相等-找到重复项.

在第二轮中(2a)小于(1a).因此,(2a)将与下一个条目进行比较.但是(1a)已经是最小的条目,并且没有上一个条目.因此,找不到(2a)的重复项并将其添加到集合中.

问:您说一个比较器不能完成两项任务,而我的第一个比较器实际上完成了两项任务.

是的-但仅适用于给定的示例.像我一样将Obj obj3a添加到集合中并运行您的代码.返回的排序集为:

[(1a), (3a), (2c)]

这违反了您对按id降序的相等值进行排序的要求.现在它通过id升序.运行我的代码,它返回正确的顺序,如上所示.

不久前与比较器作斗争时,我收到以下评论:“ …这是一个很棒的练习,展示了手动比较器实现的技巧如何……”(source)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Collectors.collectingAndThen是Java 8中的一个收集器,它将另一个收集器的结果进行进一步处理。在这个例子中,使用了Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Person::getName)))作为第一个收集器,它将根据Person对象的name属性进行去重,并将结果保存在TreeSet中。然后,通过collectingAndThen将TreeSet转换为ArrayList,作为最终的结果。 另外,还有一个类似的例子,使用了Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getName() + ";" + o.getSex())))作为第一个收集器,它将根据Person对象的name和sex属性进行去重,并将结果保存在TreeSet中。然后,通过collectingAndThen将TreeSet转换为ArrayList,作为最终的结果。 在这个去重操作中,使用了collectingAndThen和toCollection两个操作,collectingAndThen将TreeSet的结果转换为ArrayList,toCollection用于创建一个TreeSet并指定比较器。 总结起来,Collectors.collectingAndThen是一个用于收集结果并进行进一步处理的收集器,而Collectors.toCollection则用于创建一个指定类型的集合,并指定比较器来进行去重操作。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [list.stream().map().collect(Collectors.toList())](https://blog.csdn.net/shylhd/article/details/122637047)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [使用Java8 Stream流中的Collectors.collectingAndThen()方法去重](https://blog.csdn.net/qq_40474184/article/details/122043378)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值