2011-11-06 16 views
10

पर ट्यूटसेट में क्रमबद्ध म्यूटेबल ऑब्जेक्ट्स को रखना मेरे नोटिस में आया कि ऑब्जेक्ट विशेषता मान बाद में बदल दिए जाने पर ट्रीसेट क्रमबद्ध क्रम में म्यूटेबल ऑब्जेक्ट्स नहीं रखता है। उदाहरण के लिए,हर समय

public class Wrap { 
    static TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>(){ 
     @Override 
     public int compare(Student o1, Student o2) {    
      return o1.age - o2.age; 
     }  
    }); 
    public static void main(String []args){ 
     Student s = new Student(10); 
     ts.add(s); 
     ts.add(new Student(50)); 
     ts.add(new Student(30)); 
     ts.add(new Student(15)); 
     System.out.println(ts); 
     s.age = 24;  //Here I change the age of a student in the TreeSet 
     System.out.println(ts);  
    } 
} 
class Student{ 
    int age; 
    Student(int age){ 
     this.age = age; 
    } 
    @Override 
    public String toString() { 
     return "Student [age=" + age + "]"; 
    } 
} 

उत्पादन होता है:

[Student [age=10], Student [age=15], Student [age=30], Student [age=50]] 
[Student [age=24], Student [age=15], Student [age=30], Student [age=50]] 

बाद मैं एक विशेष छात्र की उम्र बदल दें और फिर TreeSet प्रिंट, सेट क्रमबद्ध क्रम में नहीं रह गया है लगता है। ऐसा क्यों होता है? और इसे हमेशा क्रमबद्ध कैसे रखा जाए?

उत्तर

10

ऐसा क्यों होता है?

क्योंकि सेट मॉनिटर सभी परिवर्तनों के लिए अपनी वस्तुओं नहीं ... कैसे यह है कि ऐसा करने में सक्षम हो जाएगा कर सकते हैं ?!

HashSets के लिए भी यही समस्या उत्पन्न होती है। HashSet ऑब्जेक्ट धारण करते समय आप किसी ऑब्जेक्ट हैश-कोड को प्रभावित करने वाले मानों को नहीं बदल सकते हैं।

और इसे हमेशा क्रमबद्ध कैसे रखा जाए?

आप आमतौर पर, सेट से तत्व निकाल इसे संशोधित, और फिर इसे फिर से लगाएं। दूसरे शब्दों में, बदल

s.age = 24;  //Here I change the age of a student in the TreeSet 

ts.remove(s); 
s.age = 24;  //Here I change the age of a student in the TreeSet 
ts.add(s); 

को तुम भी एक सूची उदाहरण के लिए उपयोग कर सकते हैं, और हर बार जब आप एक वस्तु संशोधित किया सूची पर Collections.sort कहते हैं।

+0

ठीक। किसी के बारे में कोई विचार तेजी से होगा? – aps

+2

ओ/एन लॉग एन के विपरीत निकालें/पुन: सम्मिलित हो सकता है (ओ (लॉग एन))। – aioobe

+0

'संग्रह .sort'' TreeSet' –

1

यह मानचित्र और सेट के साथ एक सामान्य समस्या है। मूल्य सम्मिलन के पल में हैशकोड/बराबर/तुलना का उपयोग करके डाले जाते हैं, और यदि वे मान जिस पर इन विधियों पर आधारित परिवर्तन होते हैं, तो संरचनाएं खराब हो सकती हैं।

एक तरीका सेट से आइटम को हटाना होगा और मान बदलने के बाद इसे फिर से जोड़ना होगा। तो यह सही होगा।

6

आप observer pattern का उपयोग कर सकते हैं। अपने TreeSet को Observer लागू करें और StudentObservable का विस्तार करें। आपको केवल एक ही बदलाव करना है जो age फ़ील्ड को encapsulation द्वारा छिपाना है ताकि आपके पास परिवर्तन पर अधिक आंतरिक नियंत्रण हो।

public class ObservableTreeSet<O extends Observable> extends TreeSet<O> implements Observer { 

    public ObservableTreeSet(Comparator<O> comparator) { 
     super(comparator); 
    } 

    @Override 
    public boolean add(O element) { 
     element.addObserver(this); 
     return super.add(element); 
    } 

    @Override 
    @SuppressWarnings("unchecked") 
    public void update(Observable element, Object arg) { 
     remove(element); 
     add((O) element); 
    } 

} 

और

public class Student extends Observable { 

    private int age; 

    Student(int age) { 
     this.age = age; 
    } 

    public int getAge() { 
     return age; 
    } 

    public void setAge(int age) { 
     if (this.age != age) { 
      setChanged(); 
     } 

     this.age = age; 

     if (hasChanged()) { 
      notifyObservers(); 
     } 
    } 

    @Override 
    public String toString() { 
     return "Student [age=" + age + "]"; 
    } 
} 

अब एक new ObservableTreeSetnew TreeSet के बजाय कार्य करें:

यहाँ एक किकऑफ़ उदाहरण है।

static TreeSet<Student> ts = new ObservableTreeSet<Student>(new Comparator<Student>() { 
    @Override 
    public int compare(Student o1, Student o2) { 
     return o1.getAge() - o2.getAge(); 
    } 
}); 

यह पहली नजर में बदसूरत है, लेकिन आप मुख्य कोड में कोई बदलाव नहीं करते हैं। बस s.setAge(24) करें और TreeSet स्वयं "पुन: व्यवस्थित" होगा।

+0

एक अच्छा प्रस्ताव है लेकिन मुझे उस समाधान के साथ समस्या है। चूंकि मैं 'setChanged()' और 'notifyObservers()' को केवल बदले गए गुणों के लिए कॉल करता हूं जो मैं 'तुलना करने के लिए() ',' निकालें (तत्व) 'में उपयोग नहीं करता क्योंकि यह काम नहीं करता है क्योंकि यह तत्व की जांच करने के लिए' तुलना करें()' का उपयोग करता है मौजूद। –

0

चमकता हुआ सूचियाँ मदद कर सकते हैं: http://www.glazedlists.com/

मैं अपने EventList के लिए इसका इस्तेमाल करते हैं और छँटाई प्रयास नहीं किया है। लेकिन अपने मुख पृष्ठ पर वे मुख्य सुविधाओं की सूची:

लाइव छंटाई का मतलब है अपनी मेज आपके डेटा में परिवर्तन के रूप अनुसार क्रमबद्ध रहता है।

0

आम तौर पर, यह सबसे अच्छा है मैन्युअल रूप से रखने के लिए अपने अनुसार क्रमबद्ध Set/Map लगातार संगत (रणनीति @aioobe ने उल्लेख किया देखें)।

हालांकि, कभी-कभी यह एक विकल्प नहीं है। इन मामलों में हम इस कोशिश कर सकते हैं:

if (treeSet.contains(item)) { 
    treeSet.remove(item); 
    treeSet.add(item); 
} 

या एक नक्शे के साथ:

if (treeMap.containsKey(key)) { 
    Value value = treeMap.get(key); 
    treeMap.remove(key); 
    treeMap.put(key, value); 
} 

लेकिन यह ठीक से काम नहीं होगा, क्योंकि यहां तक ​​कि containsKey एक गलत परिणाम के साथ हो सकता है।

तो हम एक गंदे मानचित्र के साथ क्या कर सकते हैं? पूरे मानचित्र को पुनर्निर्माण किए बिना हम एक ही कुंजी को रीफ्रेश कैसे कर सकते हैं? यहाँ इस समस्या को हल करने के लिए (आसानी से बदला जा सकता है सेट को संभालने के लिए) एक उपयोगिता वर्ग है:

public class MapUtil { 

    /** 
    * Rearranges a mutable key in a (potentially sorted) map 
    * 
    * @param map 
    * @param key 
    */ 
    public static <K, V> void refreshItem(Map<K, V> map, K key) { 
     SearchResult<K, V> result = MapUtil.searchMutableKey(map, key); 
     if (result.found) { 
      result.iterator.remove(); 
      map.put(key, result.value); 
     } 
    } 

    /** 
    * Searches a mutable key in a (potentially sorted) map 
    * 
    * Warning: currently this method uses equals() to check equality. 
    * The returned object contains three fields: 
    * - `found`: true iff the key found 
    * - `value`: the value under the key or null if `key` not found 
    * - `iterator`: an iterator pointed to the key or null if `key` not found 
    * 
    * @param map 
    * @param key 
    * @return 
    */ 
    public static <K, V> SearchResult<K, V> searchMutableKey(Map<K, V> map, K key) { 
     Iterator<Map.Entry<K, V>> entryIterator = map.entrySet().iterator(); 
     while (entryIterator.hasNext()) { 
      Map.Entry<K, V> entry = entryIterator.next(); 
      if (key.equals(entry.getKey())) { 
       return new SearchResult<K, V>(true, entry.getValue(), entryIterator); 
      } 
     } 
     return new SearchResult<K, V>(false, null, null); 
    } 

    public static class SearchResult<K, V> { 

     final public boolean found; 

     final public V value; 

     final public Iterator<Map.Entry<K, V>> iterator; 

     public SearchResult(boolean found, V value, Iterator<Map.Entry<K, V>> iterator) { 
      this.found = found; 
      this.value = value; 
      this.iterator = iterator; 
     } 

    } 

} 
0

तो आपकी समस्या को यात्रा के क्रम है, और आप TreeSet की अतिरिक्त कार्यक्षमता का उपयोग नहीं करना चाहते हैं (headSet() इत्यादि), फिर कस्टम इटरेटर के साथ HashSet का उपयोग करें। इसके अलावा, आपके उदाहरण के साथ एक बड़ी समस्या है: एक ही उम्र के दो छात्र (अक्सर ऐसा होता है) संघर्ष करते हैं।

सम्भावित समाधान:

public class Main { 

    public static void main(final String[] args) { 
     MagicSet<Student> ts = new MagicSet<Student>(new Comparator<Student>() { 

      @Override 
      public int compare(Student student1, Student student2) { 
       return student1.age - student2.age; 
      } 

     }); 

     Student s = new Student(10); 

     ts.add(s); 
     ts.add(new Student(50)); 
     ts.add(new Student(30)); 
     ts.add(new Student(15)); 

     System.out.println(ts); // 10, 15, 30, 50 
     s.age = 24; 
     System.out.println(ts); // 15, 24, 30, 50 
    } 

    public static class Student { 

     public int age; 

     public Student(int age) { 
      this.age = age; 
     } 

     @Override 
     public String toString() { 
      return "Student [age=" + age + "]"; 
     } 

    } 

    public static class MagicSet<T> extends HashSet<T> { 

     private static final long serialVersionUID = -2736789057225925894L; 

     private final Comparator<T> comparator; 

     public MagicSet(Comparator<T> comparator) { 
      this.comparator = comparator; 
     } 

     @Override 
     public Iterator<T> iterator() { 
      List<T> sortedList = new ArrayList<T>(); 
      Iterator<T> superIterator = super.iterator(); 
      while (superIterator.hasNext()) { 
       sortedList.add(superIterator.next()); 
      } 
      Collections.sort(sortedList, comparator); 
      return sortedList.iterator(); 
     } 

    } 

} 
संबंधित मुद्दे