TreeSet содержит метод не работает для меня - PullRequest
2 голосов
/ 10 июля 2011

Я хочу поместить данные пользователя в TreeSet.Когда пользовательский номер такой же, я добавляю объем сделки.

Вот мой класс TradeNode, который реализует 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.Там кто-то по имени Генри сказал мне ответ.Теперь я думаю, что когда мы используем метод contains () в TreeSet, он не ищет все в этом наборе, он только ищет отсортированное значение.

Новый класс 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 голосов
/ 10 июля 2011

TreeSet.add не делает то, что вы думаете, делает.

Если он обнаруживает, что значение уже существует, он не пытается «добавить» новое значение к существующему - он просто возвращает без изменения набора. Это просто операция на основе набора .

(Кроме того, тот факт, что ваше сравнение не синхронизировано с вашим equals методом немного странно, а сравнение this.mon == o.mon не подходит для Integer.)

0 голосов
/ 10 июля 2011

Ваш метод compareTo содержит код, который изменяет состояние o.mon += this.mon;, что является очень плохим дизайном, и, что еще хуже, это состояние используется для определения результата сравнения to if (this.mon == o.mon). Так как это ядовитое отношение существует, ваша реализация почти наверняка нарушает договор сравнения: см. его 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);  
    }  
}  
0 голосов
/ 10 июля 2011

Результат запуска: вы можете проверить, чтобы запустить программу снова.

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

вам не следует изменять его значение в методе сравнения: «o.mon + = this.mon;Это очень запутанно.

Если вы хотите суммировать все TreeNode с одинаковыми именами, не используйте коллекцию, используйте карту.

например, используйте хэш-карту, ключом является имя или (TreeNode, поскольку он равен и хеш-код использует только cstm), значение равно 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());
    }

}
}
0 голосов
/ 10 июля 2011

Вы действительно не должны мутировать аргумент в TradeNode#compareTo(...). Нет никакой гарантии, будет ли TreeSet вызывать newItem.compareTo(existingItem) или existingItem.compareTo(newItem) при сравнении.

Вы, вероятно, должны исправить свой TradeNode#compareTo(...), чтобы он выполнял Comparator контракт без мутаций.

Я не уверен, что Set (TreeSet или другое) действительно правильная структура данных, если вы хотите изменить объекты, которые в нем содержатся. Возможно, Map от String до TradeNode будет лучшим выбором?

...