У меня есть Comparator<Foo>
со следующей функцией сравнения:Как я могу убежать с непереходным компаратором?
float d = o1.bar - o2.bar;
if (Math.abs(d) <= 0.001) {
return 0;
} else {
return d < 0 ? -1 : 1; // inline Math.copySign
}
По существу, это, как предполагается сравнить два Foo
сек в зависимости от их bar
имущества, если эти значения не достаточно близки, и в этом случае они должны быть объявлены равными. (Это важно, потому что после этого я делаю другой вид, по другому свойству.)
Очевидно, что это не транзитивный компаратор. Если есть Foo
s f1
, f2
и f3
со значениями bar
как 1.999
, 2.000
и 2.001
, соответственно, то, по моему компаратор, f1==f2
и f2==f3
но f1 != f3
.
Вызов sort(myListOfFoo, myFooComparator)
дает «Метод сравнения нарушает его общий договор!». ошибка очень редко, но детерминистически.
Как использовать такой компаратор с Collections.sort(List, Comparator)
без генерирования этой ошибки?
В качестве альтернативы, есть ли способ сохранить данные, которые позволят компаратору работать правильно? Роудинг каждого поплавка до ближайшего 0.001
при строительстве будет самым простым решением, за исключением того, что поле Foo.bar
фактически рассчитывается на основе произвольной метрики расстояния, поэтому это не так просто.
Фактический код:
float d = metric.distance(vertex, o1)
- metric.distance(vertex, o2);
if (Math.abs(d) < threshold) {
return 0;
} else {
return d < 0 ? -1 : 1; // inline Math.copySign
}
, где o1
, o2
и vertex
являются экземплярами class Point { float x; float y; }
metric
и является экземпляром interface DistanceMetric { float distance(Point p1, Point p2); }
. Возможно, стоит отметить, что это не соответствует даже стандартной евклидовой метрике.
Ваше решение также не будет работать. Допустимый порог = 0,5: 2,1 округляется до 2,0, 2,4 округляется до 2,5. Следуя вашему правилу, они должны быть равны, но теперь 2.1 меньше 2.4. То же самое относится к потолку или полу. – Cristopher
@Cristopher Спасибо. Это правда, и хороший момент. Но основная причина, по которой он не будет работать, по-прежнему заключается в том, что значения не постоянны. – wchargin
В чем смысл порога, если вы просто хотите «сортировать» 'Point'? Вам нужно удалить точки на одинаковом расстоянии или что-то в этом роде? Потому что в противном случае вы можете просто использовать «нормальный» вид на основе расстояния, и все точки на «том же» расстоянии будут отсортированы правильно и будут поочередно отсортированы в отсортированном списке. –