TreeSet忽略值

时间:2017-03-28 20:22:12

标签: java sorting treeset

我正在尝试创建一个给出字符串对的类。告诉一个人是更大的"然后保持所有已知字符串的运行顺序。

要执行此操作,我会保留一个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

2 个答案:

答案 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的目的是防止无限递归。 (理论上,如果更大的是一个有向图,那绝不应该发生。)