Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java TreeSet Comparator在某些情况下无法删除重复项?_Java_Sorting_Comparator_Treeset - Fatal编程技术网

Java TreeSet Comparator在某些情况下无法删除重复项?

Java TreeSet Comparator在某些情况下无法删除重复项?,java,sorting,comparator,treeset,Java,Sorting,Comparator,Treeset,我的树集有以下比较器: public class Obj { public int id; public String value; public Obj(int id, String value) { this.id = id; this.value = value; } public String toString() { return "(" + id + value + ")"; } } O

我的树集有以下比较器:

public class Obj {
    public int id;
    public String value;
    public Obj(int id, String value) {
        this.id = id;
        this.value = value;
    }
    public String toString() {
        return "(" + id + value + ")";
    }
}

Obj obja = new Obj(1, "a");
Obj objb = new Obj(1, "b");
Obj objc = new Obj(2, "c");
Obj objd = new Obj(2, "a");
Set<Obj> set = new TreeSet<>((a, b) -> {
    System.out.println("Comparing " + a + " and " + b);
    int result = a.value.compareTo(b.value);
    if (a.id == b.id) {
        return 0;
    }
    return result == 0 ? Integer.compare(a.id, b.id) : result;
});
set.addAll(Arrays.asList(obja, objb, objc, objd));
System.out.println(set);
公共类Obj{
公共int id;
公共字符串值;
公共对象(整数id,字符串值){
this.id=id;
这个值=值;
}
公共字符串toString(){
返回“(“+id+value+”)”;
}
}
Obj obja=新Obj(1,“a”);
Obj objb=新Obj(1,“b”);
Obj objc=新的Obj(2,“c”);
Obj objd=新的Obj(2,“a”);
集合集合=新树集合((a,b)->{
System.out.println(“比较“+a+”和“+b”);
int结果=a.value.compareTo(b.value);
如果(a.id==b.id){
返回0;
}
返回结果==0?整数。比较(a.id,b.id):结果;
});
addAll(Arrays.asList(obja、objb、objc、objd));
系统输出打印项次(套);
它打印出[(1a),(2c)],删除了重复项

但是,当我将最后一个
整数.compare
更改为
整数.compare(b.id,a.id)
(即切换a和b的位置)时,它会打印出[(2a)、(1a)、(2c)]。显然,相同的id 2出现了两次

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

您在问:
如何修复比较器,使其始终根据id删除重复项,并根据值(升序)然后根据id(降序)对有序集进行排序

你想让比较器

  • 根据
    Obj.id
  • Obj.value
    Obj.id
  • 要求1)导致

    Function<Obj, Integer> byId = o -> o.id;
    Set<Obj> setById = new TreeSet<>(Comparator.comparing(byId));
    
    Function<Obj, String> byValue = o -> o.value;
    Comparator<Obj> sortingComparator =  Comparator.comparing(byValue).thenComparing(Comparator.comparing(byId).reversed());
    Set<Obj> setByValueAndId = new TreeSet<>(sortingComparator);
    
    或者,如果不需要集合本身,但要按所需顺序处理元素,则可以使用

    Consumer<Obj> consumer = <your consumer>;
    setById.stream().sorted(sortingComparator).forEach(consumer);
    
    // instantiating one additional Obj and reusing those from the question
    Obj obj3a = new Obj(3, "a");
    
    // reusing sortingComparator from the code above
    Set<Obj> set = Stream.of(obja, objb, objc, objd, obj3a)
            .distinct()
            .sorted(sortingComparator)
            .collect(Collectors.toCollection(LinkedHashSet::new));
    
    System.out.println(set); // [(3a), (1a), (2c)]
    
    现在我们可以使用

    Consumer<Obj> consumer = <your consumer>;
    setById.stream().sorted(sortingComparator).forEach(consumer);
    
    // instantiating one additional Obj and reusing those from the question
    Obj obj3a = new Obj(3, "a");
    
    // reusing sortingComparator from the code above
    Set<Obj> set = Stream.of(obja, objb, objc, objd, obj3a)
            .distinct()
            .sorted(sortingComparator)
            .collect(Collectors.toCollection(LinkedHashSet::new));
    
    System.out.println(set); // [(3a), (1a), (2c)]
    
    运行代码一次,然后切换
    整数的操作数。比较
    。该开关会导致不同的比较路径。区别在于比较
    (2a)
    (1a)

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

    在第二次运行中,
    (2a)
    小于
    (1a)
    。因此,
    (2a)
    将作为下一个条目与上一个条目进行比较。但是
    (1a)
    已经是最小的条目,并且没有以前的条目。因此,未发现
    (2a)
    的重复项,并将其添加到集合中

    问:你说一个比较器不能完成两项任务,我的第一个比较器实际上两项任务都做得很好。
    是-但仅针对给定示例。像我一样将
    Obj obj3a
    添加到集合中并运行代码。返回的排序集为:

    [(1a), (3a), (2c)]
    
    这违反了按
    id
    降序的相等
    value
    s排序的要求。现在它的升序是
    id
    。运行我的代码,它返回正确的顺序,如上所示


    一段时间前,我在与比较器搏斗时得到了以下评论:“……这是一个很好的练习,演示了手动比较器实现有多么棘手……”(

    在每种情况下,您希望得到的确切结果是什么?谢谢。这就是为什么我选择TreeSet来进行自定义和排序。但我不明白为什么不可能实现我想要的?相等部分在我的比较器中完成,因此返回0以删除重复项。只有在这之后才有排序逻辑(即不重复)。我扩展了我的答案。很棒的东西!我感谢您为我们找到解决方案所做的努力,但您能否评论一下在我的原始比较器中返回0的效果?我想这是我的主要问题:返回0不意味着在treeset比较器中删除重复项吗?如果是这样,为什么它没有正确完成工作?尽管你说一个比较器不能完成两个任务,但我的第一个比较器实际上正确地完成了两个任务。这让我很困惑,因此我提出了这个问题。我很可能会同意“永远不要在比较中做两件事”。对于“或者结果不能保证”这一部分,我不同意,因为在大多数情况下,结果应该是确定的。因此,结果可能是有保证的(因为它是可预测的),但它可能不是正确的。对我来说,主要结论是,学会理解我们想要使用或实施的东西的责任。这一责任可能取决于具体情况。用于初始化树集的
    比较器
    负责区分元素和
    集合中的元素。排序(列表l)
    负责它们的顺序。
    [(1a), (3a), (2c)]