TreeSet Comparator failed to remove duplicates in some cases?











up vote
0
down vote

favorite












I have the following comparator for my 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 + ")";
}
}

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);


It prints out [(1a), (2c)], which removed the duplicates.



But when I changed the last Integer.compare to Integer.compare(b.id, a.id) (i.e. switched the positions of a and b), it prints out [(2a), (1a), (2c)]. Clearly the same id 2 appeared twice.



How do you fix the comparator to always remove the duplicates based on ids and sort the ordered set based on value (ascending) then id (descending)?










share|improve this question






















  • What is your exact desired result in each case?
    – Ole V.V.
    16 hours ago















up vote
0
down vote

favorite












I have the following comparator for my 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 + ")";
}
}

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);


It prints out [(1a), (2c)], which removed the duplicates.



But when I changed the last Integer.compare to Integer.compare(b.id, a.id) (i.e. switched the positions of a and b), it prints out [(2a), (1a), (2c)]. Clearly the same id 2 appeared twice.



How do you fix the comparator to always remove the duplicates based on ids and sort the ordered set based on value (ascending) then id (descending)?










share|improve this question






















  • What is your exact desired result in each case?
    – Ole V.V.
    16 hours ago













up vote
0
down vote

favorite









up vote
0
down vote

favorite











I have the following comparator for my 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 + ")";
}
}

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);


It prints out [(1a), (2c)], which removed the duplicates.



But when I changed the last Integer.compare to Integer.compare(b.id, a.id) (i.e. switched the positions of a and b), it prints out [(2a), (1a), (2c)]. Clearly the same id 2 appeared twice.



How do you fix the comparator to always remove the duplicates based on ids and sort the ordered set based on value (ascending) then id (descending)?










share|improve this question













I have the following comparator for my 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 + ")";
}
}

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);


It prints out [(1a), (2c)], which removed the duplicates.



But when I changed the last Integer.compare to Integer.compare(b.id, a.id) (i.e. switched the positions of a and b), it prints out [(2a), (1a), (2c)]. Clearly the same id 2 appeared twice.



How do you fix the comparator to always remove the duplicates based on ids and sort the ordered set based on value (ascending) then id (descending)?







java sorting comparator treeset






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked 17 hours ago









user1589188

1,55782764




1,55782764












  • What is your exact desired result in each case?
    – Ole V.V.
    16 hours ago


















  • What is your exact desired result in each case?
    – Ole V.V.
    16 hours ago
















What is your exact desired result in each case?
– Ole V.V.
16 hours ago




What is your exact desired result in each case?
– Ole V.V.
16 hours ago












1 Answer
1






active

oldest

votes

















up vote
0
down vote













You're askimg:
How do you fix the comparator to always remove the duplicates based on ids and sort the ordered set based on value (ascending) then id (descending)?



You want the comparator to




  1. remove duplicates based on Obj.id

  2. sort the set by Obj.alue and Obj.id


Requirement 1) results in



Function<Obj, Integer> byId = o -> o.id;
Set<Obj> setById = new TreeSet<>(Comparator.comparing(byId));


Requirement 2) results in



Function<Obj, String> byValue = o -> o.value;
Comparator<Obj> sortingComparator = Comparator.comparing(byValue).thenComparing(Comparator.comparing(byId).reversed());
Set<Obj> setByValueAndId = new TreeSet<>(sortingComparator);


Let's have a look on the JavaDoc of TreeSet. It says:




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.




The set will be ordered according to the comparator but its elements are also compared for equality using the comparator.



As far as I can see there is no way to define a Comparator which satisfies both requirements. Since a TreeSet is in the first place a Set requirement 1) has to match. To achieve requirement 2) you can create a second TreeSet:



Set<Obj> setByValueAndId = new TreeSet<>(sortingComparator);
setByValueAndId.addAll(setById);


Or if you don't need the set itself but to process the elements in the desired order you can use a Stream:



Consumer<Obj> consumer = <your consumer>;
setById.stream().sorted(sortingComparator).forEach(consumer);


BTW:

While it's possible to sort the elements of a Stream according to a given Comparator there is no distinct method taking a Comparator to remove duplicates according to it.






share|improve this answer























  • Thanks. Thats why I chose TreeSet to do both the custom distinct and sorting. But I don't understand how it is impossible to achieve what I want? The equality part is done in my comparator, hence the returning of 0 for duplicates removal. Only after that there goes the sorting logic (i.e. not duplicates).
    – user1589188
    2 hours ago











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














 

draft saved


draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53371148%2ftreeset-comparator-failed-to-remove-duplicates-in-some-cases%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
0
down vote













You're askimg:
How do you fix the comparator to always remove the duplicates based on ids and sort the ordered set based on value (ascending) then id (descending)?



You want the comparator to




  1. remove duplicates based on Obj.id

  2. sort the set by Obj.alue and Obj.id


Requirement 1) results in



Function<Obj, Integer> byId = o -> o.id;
Set<Obj> setById = new TreeSet<>(Comparator.comparing(byId));


Requirement 2) results in



Function<Obj, String> byValue = o -> o.value;
Comparator<Obj> sortingComparator = Comparator.comparing(byValue).thenComparing(Comparator.comparing(byId).reversed());
Set<Obj> setByValueAndId = new TreeSet<>(sortingComparator);


Let's have a look on the JavaDoc of TreeSet. It says:




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.




The set will be ordered according to the comparator but its elements are also compared for equality using the comparator.



As far as I can see there is no way to define a Comparator which satisfies both requirements. Since a TreeSet is in the first place a Set requirement 1) has to match. To achieve requirement 2) you can create a second TreeSet:



Set<Obj> setByValueAndId = new TreeSet<>(sortingComparator);
setByValueAndId.addAll(setById);


Or if you don't need the set itself but to process the elements in the desired order you can use a Stream:



Consumer<Obj> consumer = <your consumer>;
setById.stream().sorted(sortingComparator).forEach(consumer);


BTW:

While it's possible to sort the elements of a Stream according to a given Comparator there is no distinct method taking a Comparator to remove duplicates according to it.






share|improve this answer























  • Thanks. Thats why I chose TreeSet to do both the custom distinct and sorting. But I don't understand how it is impossible to achieve what I want? The equality part is done in my comparator, hence the returning of 0 for duplicates removal. Only after that there goes the sorting logic (i.e. not duplicates).
    – user1589188
    2 hours ago















up vote
0
down vote













You're askimg:
How do you fix the comparator to always remove the duplicates based on ids and sort the ordered set based on value (ascending) then id (descending)?



You want the comparator to




  1. remove duplicates based on Obj.id

  2. sort the set by Obj.alue and Obj.id


Requirement 1) results in



Function<Obj, Integer> byId = o -> o.id;
Set<Obj> setById = new TreeSet<>(Comparator.comparing(byId));


Requirement 2) results in



Function<Obj, String> byValue = o -> o.value;
Comparator<Obj> sortingComparator = Comparator.comparing(byValue).thenComparing(Comparator.comparing(byId).reversed());
Set<Obj> setByValueAndId = new TreeSet<>(sortingComparator);


Let's have a look on the JavaDoc of TreeSet. It says:




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.




The set will be ordered according to the comparator but its elements are also compared for equality using the comparator.



As far as I can see there is no way to define a Comparator which satisfies both requirements. Since a TreeSet is in the first place a Set requirement 1) has to match. To achieve requirement 2) you can create a second TreeSet:



Set<Obj> setByValueAndId = new TreeSet<>(sortingComparator);
setByValueAndId.addAll(setById);


Or if you don't need the set itself but to process the elements in the desired order you can use a Stream:



Consumer<Obj> consumer = <your consumer>;
setById.stream().sorted(sortingComparator).forEach(consumer);


BTW:

While it's possible to sort the elements of a Stream according to a given Comparator there is no distinct method taking a Comparator to remove duplicates according to it.






share|improve this answer























  • Thanks. Thats why I chose TreeSet to do both the custom distinct and sorting. But I don't understand how it is impossible to achieve what I want? The equality part is done in my comparator, hence the returning of 0 for duplicates removal. Only after that there goes the sorting logic (i.e. not duplicates).
    – user1589188
    2 hours ago













up vote
0
down vote










up vote
0
down vote









You're askimg:
How do you fix the comparator to always remove the duplicates based on ids and sort the ordered set based on value (ascending) then id (descending)?



You want the comparator to




  1. remove duplicates based on Obj.id

  2. sort the set by Obj.alue and Obj.id


Requirement 1) results in



Function<Obj, Integer> byId = o -> o.id;
Set<Obj> setById = new TreeSet<>(Comparator.comparing(byId));


Requirement 2) results in



Function<Obj, String> byValue = o -> o.value;
Comparator<Obj> sortingComparator = Comparator.comparing(byValue).thenComparing(Comparator.comparing(byId).reversed());
Set<Obj> setByValueAndId = new TreeSet<>(sortingComparator);


Let's have a look on the JavaDoc of TreeSet. It says:




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.




The set will be ordered according to the comparator but its elements are also compared for equality using the comparator.



As far as I can see there is no way to define a Comparator which satisfies both requirements. Since a TreeSet is in the first place a Set requirement 1) has to match. To achieve requirement 2) you can create a second TreeSet:



Set<Obj> setByValueAndId = new TreeSet<>(sortingComparator);
setByValueAndId.addAll(setById);


Or if you don't need the set itself but to process the elements in the desired order you can use a Stream:



Consumer<Obj> consumer = <your consumer>;
setById.stream().sorted(sortingComparator).forEach(consumer);


BTW:

While it's possible to sort the elements of a Stream according to a given Comparator there is no distinct method taking a Comparator to remove duplicates according to it.






share|improve this answer














You're askimg:
How do you fix the comparator to always remove the duplicates based on ids and sort the ordered set based on value (ascending) then id (descending)?



You want the comparator to




  1. remove duplicates based on Obj.id

  2. sort the set by Obj.alue and Obj.id


Requirement 1) results in



Function<Obj, Integer> byId = o -> o.id;
Set<Obj> setById = new TreeSet<>(Comparator.comparing(byId));


Requirement 2) results in



Function<Obj, String> byValue = o -> o.value;
Comparator<Obj> sortingComparator = Comparator.comparing(byValue).thenComparing(Comparator.comparing(byId).reversed());
Set<Obj> setByValueAndId = new TreeSet<>(sortingComparator);


Let's have a look on the JavaDoc of TreeSet. It says:




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.




The set will be ordered according to the comparator but its elements are also compared for equality using the comparator.



As far as I can see there is no way to define a Comparator which satisfies both requirements. Since a TreeSet is in the first place a Set requirement 1) has to match. To achieve requirement 2) you can create a second TreeSet:



Set<Obj> setByValueAndId = new TreeSet<>(sortingComparator);
setByValueAndId.addAll(setById);


Or if you don't need the set itself but to process the elements in the desired order you can use a Stream:



Consumer<Obj> consumer = <your consumer>;
setById.stream().sorted(sortingComparator).forEach(consumer);


BTW:

While it's possible to sort the elements of a Stream according to a given Comparator there is no distinct method taking a Comparator to remove duplicates according to it.







share|improve this answer














share|improve this answer



share|improve this answer








edited 12 hours ago

























answered 12 hours ago









LuCio

2,4491722




2,4491722












  • Thanks. Thats why I chose TreeSet to do both the custom distinct and sorting. But I don't understand how it is impossible to achieve what I want? The equality part is done in my comparator, hence the returning of 0 for duplicates removal. Only after that there goes the sorting logic (i.e. not duplicates).
    – user1589188
    2 hours ago


















  • Thanks. Thats why I chose TreeSet to do both the custom distinct and sorting. But I don't understand how it is impossible to achieve what I want? The equality part is done in my comparator, hence the returning of 0 for duplicates removal. Only after that there goes the sorting logic (i.e. not duplicates).
    – user1589188
    2 hours ago
















Thanks. Thats why I chose TreeSet to do both the custom distinct and sorting. But I don't understand how it is impossible to achieve what I want? The equality part is done in my comparator, hence the returning of 0 for duplicates removal. Only after that there goes the sorting logic (i.e. not duplicates).
– user1589188
2 hours ago




Thanks. Thats why I chose TreeSet to do both the custom distinct and sorting. But I don't understand how it is impossible to achieve what I want? The equality part is done in my comparator, hence the returning of 0 for duplicates removal. Only after that there goes the sorting logic (i.e. not duplicates).
– user1589188
2 hours ago


















 

draft saved


draft discarded



















































 


draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53371148%2ftreeset-comparator-failed-to-remove-duplicates-in-some-cases%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Tonle Sap (See)

I get strange results when I access the Sqlitedatabase with Unity C# via XAMPP

Guatemaltekische Davis-Cup-Mannschaft