2

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

这是我TradeNode实现ComparableInterator 的类。

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 得到了答案。有个叫亨利的人告诉我答案。现在我认为当我们在 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

4 回答 4

4

TreeSet.add不做你认为它做的事。

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

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

于 2011-07-10T11:45:39.027 回答
0

你真的不应该在TradeNode#compareTo(...). 无法保证是否TreeSet会调用newItem.compareTo(existingItem)existingItem.compareTo(newItem)进行比较。

您可能应该修复您的TradeNode#compareTo(...),以便它在Comparator没有突变的情况下履行合同。

如果您想改变它包含的对象,我不确定 a Set(或其他) 是否真的是正确的数据结构。TreeSet也许MapStringTradeNode将是更好的选择?

于 2011-07-10T12:31:14.063 回答
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 时,检查是否存在相同的名称,如果不存在,则添加到地图,否则添加值。

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

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

}
}
于 2011-07-10T12:32:50.400 回答
0

您的 compareTo 方法包含更改 state 的代码o.mon += this.mon;,这是非常糟糕的设计,更糟糕的是,该 state 用于确定 compareTo 的结果if (this.mon == o.mon)。由于存在这种有害关系,因此您的实现几乎肯定违反了 compareTo 的合同:请参阅它的 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);  
    }  
}  
于 2011-07-10T12:35:02.860 回答