我正在尝试创建一个给出字符串对的类。告诉一个人是更大的"然后保持所有已知字符串的运行顺序。
要执行此操作,我会保留一个Map<String, Set<String>>
,将给定的String
映射到大于它的所有值,然后我创建一个TreeSet
,其中包含一个使用该值的比较器用于比较两个字符串的数据。
这是我的班级:
public class StringSorter {
private Map<String, Set<String>> greaterThan = new HashMap<>();
private SortedSet<String> order;
public StringSorter() {
order = new TreeSet<>((o1, o2) -> {
if (greaterThan.getOrDefault(o1, Collections.emptySet()).contains(o2))
return 1;
else if (greaterThan.getOrDefault(o2, Collections.emptySet()).contains(o1))
return -1;
return 0;
});
}
public void addRule(String bigger, String smaller) {
if (!greaterThan.containsKey(bigger))
greaterThan.put(bigger, new HashSet<>());
greaterThan.get(bigger).add(smaller);
order.add(bigger);
order.add(smaller);
}
public SortedSet<String> getOrder() {
return order;
}
}
但是,出于某种原因,TreeSet
似乎只是忽略了添加到它的许多值。
示例:
StringSorter sorter = new StringSorter();
sorter.addRule("one", "two");
sorter.addRule("two", "three");
sorter.addRule("three", "four");
System.out.println(sorter.getOrder());
输出:
[two, one]
字符串three
&amp; four
?
答案 0 :(得分:1)
问题是set集合保留了唯一值。 调试比较器后,您将看到“三”被评估为等于“一”,因此禁止将其添加到集合中。
考虑这个修改:
public StringSorter() {
order = new TreeSet<>((o1, o2) -> {
if (greaterThan.getOrDefault(o1, Collections.emptySet()).contains(o2))
return 1;
else if (greaterThan.getOrDefault(o2, Collections.emptySet()).contains(o1))
return -1;
else if(o1.equals(o2)) return 0;
else return -1; //or 1, or o1.compareTo(o2)
});
}
我们首先检查对象是否相等,如果不是,则比较本身是无关紧要的,结果可能是任意的。
这是使用更新的比较器时的输出:
[four, three, two, one]
[编辑]
我会考虑将规则的内部表示更改为面向自定义的树数据结构,由稀疏邻接矩阵表示。
答案 1 :(得分:1)
您可以通过将此行添加到Comparator.compare lambda:
来自行回答System.out.printf("(%s, %s)%n", o1, o2);
正如您将看到的,无法保证将相邻值传递给Comparator。当o1
为“3”并且o2
为“1”时,比较将返回到零,这告诉TreeSet这两个值是相等的,显然它不会添加值感知等于已经在集合中的值。
您需要对greaterThan
传递进行遍历。我很确定它需要递归:
private boolean isGreater(String o1,
String o2,
Set<String> keysTried) {
Set<String> greaterSet = greaterThan.get(o1);
if (greaterSet == null) {
return false;
}
if (greaterSet.contains(o2)) {
return true;
}
for (String g : greaterSet) {
if (keysTried.add(g) && isGreater(g, o2, keysTried)) {
return true;
}
}
return false;
}
public StringSorter() {
order = new TreeSet<>((o1, o2) -> {
if (isGreater(o1, o2, new HashSet<>())) {
return 1;
} else if (isGreater(o2, o1, new HashSet<>())) {
return -1;
} else {
return 0;
}
});
}
keysTried
的目的是防止无限递归。 (理论上,如果更大的是一个有向图,那绝不应该发生。)