TreeSet包含的方法对我不起作用

时间:2011-07-10 11:41:15

标签: java contains treeset

我想将自定义数据放入TreeSet。当自定义数字相同时,我会添加交易量。

这是实现TradeNode Interator的Comparable类。

import java.util.Comparator;  

public class TradeNode implements Comparable<TradeNode> {  

    private String cstm; // custom number  

    private Integer mon = 0; // Trade  

    public TradeNode() {}  

    public TradeNode(String cstm, int mon) {  
        this.mon = mon;  
        this.cstm = cstm;  
    }  

    public int compareTo(TradeNode o) {  
        if (o.cstm.equals(this.cstm)) {  
            o.mon += this.mon;  
            return 0;  
        } else if (this.mon == o.mon) {  
            return this.cstm.compareTo(o.cstm);  
        } else {  
            //return (o.mon - this.mon);  
            return o.mon.compareTo(this.mon);  
        }  
    }  

    @Override  
    public boolean equals(Object obj) {  
        if (this == obj) {  
            return true;  
        }  
        if (obj == null) {  
            return false;  
        }  
        if (!(obj instanceof TradeNode)) {  
            return false;  
        }  
        TradeNode other = (TradeNode) obj;  
        if (cstm == null) {  
            if (other.cstm != null) {  
                return false;  
            }  
        } else if (!cstm.equals(other.cstm)) {  
            return false;  
        }  
        return true;  
    }  

    @Override  
    public int hashCode() {  
        final int prime = 31;  
        int result = 1;  
        result = prime * result + ((cstm == null) ? 0 : cstm.hashCode());  
        return result;  
    }  

    @Override  
    public String toString() {  
        return "[" + cstm + "] [" + mon + "]";  
    }  

    public int getMon() {  
        return mon;  
    }  

    public void setMon(Integer mon) {  
        this.mon = mon;  
    }  

    public String getCstm() {  
        return cstm;  
    }  

} 

,测试类是:

public class Testtree {  
    public static void main(String[] args) {  
    TradeNode nd1 = new TradeNode("A", 100);  
        TradeNode nd2 = new TradeNode("B", 10);  
        TradeNode nd3 = new TradeNode("B", 1000);  
        TreeSet<TradeNode> tree = new TreeSet<TradeNode>();  
        tree.add(nd1);  
        tree.add(nd2);  
        tree.add(nd3);  
        for (TradeNode node : tree) {  
            System.out.println(node);  
        }  
    } 

我认为输出应该是这样的:

[B] [1010]  
[A] [100]

但输出是

[B] [1000]  
[A] [100] 
[B] [10]

有人可以帮助我并指出我的错吗?

如果我像这样更改compareTo()方法,它仍然不起作用。

public int compareTo(TradeNode o) {
        if (o.cstm.equals(this.cstm)) {
            return 0;
        } else {
            return o.mon.compareTo(this.mon);
        }
    }

结果是:

[B] [1000]
[A] [100]
[B] [10]

我尝试了 Ben Xu 的方法,这里是代码: 我的新compareTo()方法:

public int compareTo(TradeNode o) {
        if (o.cstm.equals(this.cstm)) {
            return 0;
        } else {
            return this.mon.compareTo(o.mon);
        }
    }

我的新Testtree课程:

public class Testtree {

    public static void main(String[] args) {
        TradeNode nd1 = new TradeNode("44010358010481", 150354);
        TradeNode nd2 = new TradeNode("44010358010481", 150641);
        TradeNode nd3 = new TradeNode("44010358010481", 270000);
        TradeNode nd4 = new TradeNode("44010039275685", 10000);
        TradeNode nd5 = new TradeNode("44010039275685", 980000);
        TradeNode nd6 = new TradeNode("44010039275685", 5000);
        TradeNode nd7 = new TradeNode("44010234235687", 10000);
        TradeNode nd8 = new TradeNode("44010234235687", 360000);
        TradeNode nd9 = new TradeNode("44010234235687", 53400);
        Map<String, Integer> map = new HashMap<String, Integer>(); 
        addTradeNode(map, nd1);
        addTradeNode(map, nd2);
        addTradeNode(map, nd3);
        addTradeNode(map, nd4);
        addTradeNode(map, nd5);
        addTradeNode(map, nd6);
        addTradeNode(map, nd7);
        addTradeNode(map, nd8);
        addTradeNode(map, nd9);

        Iterator<Entry<String, Integer>> iterator = map.entrySet().iterator();
        TradeNode t;
        List<TradeNode> list = new ArrayList<TradeNode>();
        while(iterator.hasNext()) {
            Map.Entry<String, Integer> m = iterator.next();
            t = new TradeNode(m.getKey(),m.getValue());
            list.add(t);
        }
        Collections.sort(list);
        for(TradeNode tn : list) {
            System.out.println(tn);
        }
    }

    private static void addTradeNode(Map<String, Integer> map, TradeNode node) {

        Integer integer = map.get(node.getCstm());
        if (integer == null) {
            map.put(node.getCstm(), node.getMon());
        } else {
            map.remove(node.getCstm());
            map.put(node.getCstm(), integer.intValue() + node.getMon());
        }

    }

}

结果是:

[44010234235687] [423400]
[44010358010481] [570995]
[44010039275685] [995000]

最后,它满足了我的要求。但我仍然不知道为什么这个新的compareTo()方法在以下测试方法中不起作用:

public class Testtree2 {

    public static void main(String[] args) {
        TradeNode nd1 = new TradeNode("A", 100);
        TradeNode nd2 = new TradeNode("B", 10);
        TradeNode nd3 = new TradeNode("B", 1000);
        TreeSet<TradeNode> tree = new TreeSet<TradeNode>();
        tree.add(nd1);
        tree.add(nd2);
        tree.add(nd3);
        for (TradeNode node : tree) {
            System.out.println(node);
        }       
    }
}

结果是:

[B] [10]
[A] [100]
[B] [1000]

我认为是:

[B] [10]
[A] [100]

有人能告诉我新的compareTo()方法中的错误在哪里吗?非常感谢,感谢任何帮助我的人。

哈哈哈,我从JavaRanch那里得到了答案。有一个名叫 Henry 的人告诉我答案。现在我想当我们在TreeSet中使用contains()方法时,它不会搜索此Set中的所有内容,它只搜索已排序的值。

新的Testtree3类是:

public class Testtree3 {

    public static void main(String[] args) {
    TradeNode nd1 = new TradeNode("A", 100);
        TradeNode nd2 = new TradeNode("B", 200);
        TradeNode nd3 = new TradeNode("B", 1000);
        TreeSet<TradeNode> tree = new TreeSet<TradeNode>();
        tree.add(nd1);
        tree.add(nd2);
        tree.add(nd3);
        for (TradeNode node : tree) {
            System.out.println(node);
        }
    }

}

结果是:

[A] [100]
[B] [200]

哈哈。现在我将找到TreeSet背后的代码。

4 个答案:

答案 0 :(得分:4)

TreeSet.add没有按照您的想法行事。

如果它检测到某个值已经存在,则它不会尝试将新值“添加”到现有值 - 它只返回而不更改集合。它只是一个基于集合的操作。

(此外,您的比较与equals方法不同步的事实有点奇怪,this.mon == o.mon的比较不适合Integer。)

答案 1 :(得分:0)

你真的不应该在TradeNode#compareTo(...)中改变这个论点。在进行比较时,无法保证TreeSet是否会调用newItem.compareTo(existingItem)existingItem.compareTo(newItem)

你应该修复你的TradeNode#compareTo(...),使其符合Comparator合约而不会发生突变。

如果你想改变它包含的对象,我不确定SetTreeSet或其他)是否是正确的数据结构。也许从MapString的{​​{1}}会是更好的选择吗?

答案 2 :(得分:0)

运行结果是,您可以检查再次运行程序。

[B] [1000]
[A] [100]
[B] [10]

结果是由于treeset使用了您实现的比较器

我不知道你想做什么。

但至少有一个明显的不良做法:

public int compareTo(TradeNode o) {  
    if (o.cstm.equals(this.cstm)) {  
        o.mon += this.mon;  
        return 0;  
    } else if (this.mon == o.mon) {  
        return this.cstm.compareTo(o.cstm);  
    } else {  
        //return (o.mon - this.mon);  
        return o.mon.compareTo(this.mon);  
    }  
}  

你不应该在compareTo方法中更改它的值“o.mon + = this.mon; “,这非常令人困惑。

如果要将所有TreeNode的名称相加, 不要使用Collection,而是使用map。

例如,使用hashmap,key是name或(TreeNode,因为它的equals和hashcode只使用cstm),value是num。每次添加TreeNode时,检查是否存在相同的名称,如果没有,则添加到map,否则添加值。

以下是使用map的一个示例代码:

public class Testtree {
public static void main(String[] args) {
    TradeNode nd1 = new TradeNode("A", 100);
    TradeNode nd2 = new TradeNode("B", 10);
    TradeNode nd3 = new TradeNode("B", 1000);
    Map<String, Integer> map = new HashMap<String, Integer>();
    addTreeNode(map, nd1);
    addTreeNode(map, nd2);
    addTreeNode(map, nd3);
    System.out.println(map);
}

private static void addTreeNode(Map<String, Integer> map, TradeNode node) {

    Integer integer = map.get(node.getCstm());
    if (integer == null) {
        map.put(node.getCstm(), node.getMon());
    } else {
        map.remove(node.getCstm());
        map.put(node.getCstm(), integer.intValue() + node.getMon());
    }

}
}

答案 3 :(得分:0)

您的compareTo方法包含更改状态o.mon += this.mon;的代码,这是非常糟糕的设计,更糟糕的是,该状态用于确定compareTo if (this.mon == o.mon)的结果。由于存在这种毒性关系,您的实施几乎肯定违反了比较合同:见its javadoc

这太可怕了。摆脱compareTo方法中的副作用样式状态更改。

public int compareTo(TradeNode o) {  
    if (o.cstm.equals(this.cstm)) {  
        o.mon += this.mon;    // ALARM BELLS!!! SIDE EFFECT!! ARRGGGHHH!
        return 0;  
    } else if (this.mon == o.mon) {  // AND THE SIDE EFFECT IS ALSO USED TO COMPARE! AVERT YOUR EYES! 
        return this.cstm.compareTo(o.cstm);  
    } else {  
        //return (o.mon - this.mon);  
        return o.mon.compareTo(this.mon);  
    }  
}