12

名前と時間の属性を持つオブジェクトで満たされた ArrayList があります。名前に基づいて重複を削除し、最新の時間の記録のみを保持したいと考えています。そのため、オブジェクトの名前をオーバーライドequalsし、hashcodeこのようなコードを使用しました。

private List<ChangedRecentlyTO> groupRecords(List<ChangedRecentlyTO> toList) {
    changedRecentlyList.clear(); //static list
    for(ChangedRecentlyTO to : toList) {
        if(!changedRecentlyList.contains(to)) {
            changedRecentlyList.add(to);
        } else {
            if(changedRecentlyList.get(changedRecentlyList.lastIndexOf(to)).getTimeChanged().before(to.getTimeChanged())) {
                changedRecentlyList.remove(to);
                changedRecentlyList.add(to);
            }
        }
    }
    return changedRecentlyList;
}

しかし、もっと良い解決策はありますか? Set を使用することを考えていましたが、時間基準をどのように配置すればよいかわかりません。

4

7 に答える 7

5

新しいオブジェクトが既存のオブジェクトよりも新しい場合にのみ配置するようにメソッドを拡張HashMapおよびオーバーライドします。put

HashMapまたは、の一部の実装がStackによってサポートされるように、によってサポートされる独自の専用コンテナを作成できます。LinkedList


これはモックコードです:

import java.util.HashMap;
import java.util.Map;

public class TimeMap<K, V> {

    private Map<K, V> timeMap;

    public TimeMap() {
        this.timeMap = new HashMap<K, V>();
    }

    public void put(K key, V value) {
        if (isNewer(key, value)) {
            this.timeMap.put(key, value);
        }
    }

}
于 2012-07-12T08:57:33.817 に答える
5

セットがどのように機能するかを理解する必要がある方法と、Java Collections についてほとんど理解していない人にとってより理解しやすい方法の 2 つの方法があります。

単純にしたい場合は、Set の Javadoc の詳細を読むだけですhttp://docs.oracle.com/javase/6/docs/api/java/util/Set.html#add(E ) . 要素が既に内部にある場合は、再度追加されないことを明確に示しています。

  • 名前だけを使用して equals と hashcode を実装します
  • アイテムを時間で並べ替えてから、セットに追加します。

このように、アイテムを Set に初めて追加するときは、最新の時刻の要素を追加することになります。他のものを追加すると、それらは既に含まれているため無視されます。


java.util.Set のコントラクトを正確に知らない他の誰かが動作する場合、意図を明確にするために Set を拡張することをお勧めします。ただし、「削除後に要素を取得する」ためにセットにアクセスすることは想定されていないため、セットを HashMap でバックアップする必要があります。

interface TimeChangeable {
   long getTimeChanged();
}
public class TimeChangeableSet<E extends TimeCheangeable> implements Set<E> {

    private final HashMap<Integer,E> hashMap = new HashMap<Integer,E>();

    @Override
    public boolean add(E e) {
        E existingValue = hashMap.remove(e.hashCode());
        if(existingValue==null){
            hashMap.put(e.hashCode(),e);
            return true;
        }
        else{
            E toAdd = e.getTimeChanged() > existingValue.getTimeChanged() ? e : existingValue;
            boolean newAdded = e.getTimeChanged() > existingValue.getTimeChanged() ? true : false;
            hashMap.put(e.hashCode(),e);
            return newAdded;
        }

    }

    @Override
    public int size() {
        return hashMap.size();
    }

    @Override
    public boolean isEmpty() {
        return hashMap.isEmpty();
    }

    @Override
    public boolean contains(Object o) {
        return hashMap.containsKey(o.hashCode());
    }

    @Override
    public Iterator<E> iterator() {
        return hashMap.values().iterator();
    }

    @Override
    public Object[] toArray() {
        return hashMap.values().toArray();
    }

    @Override
    public <T> T[] toArray(T[] a) {
        return hashMap.values().toArray(a);
    }

    @Override
    public boolean remove(Object o) {
        return removeAndGet(o)!=null ? true : false;
    }

    public E removeAndGet (Object o) {
        return hashMap.remove(o.hashCode());
    }

    @Override
    public boolean containsAll(Collection<?> c) {
        boolean containsAll = true;
        for(Object object:c){
            E objectInMap = removeAndGet(object);
            if(objectInMap==null || !objectInMap.equals(object))
                containsAll=false;
        }
        return containsAll;
    }

    @Override
    public boolean addAll(Collection<? extends E> c) {
        boolean  addAll=true;
        for(E e:c){
            if(!add(e)) addAll=false;
        }
        return addAll;

    }

    @Override
    public boolean retainAll(Collection<?> c) {
        boolean setChanged=false;
        for(E e: hashMap.values()){
            if(!c.contains(e)){
                hashMap.remove(e.hashCode());
                setChanged=true;
            }
        }
        return setChanged;
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        throw new UnsupportedOperationException("Please do not use type-unsafe methods in 2012");
    }

    @Override
    public void clear() {
        hashMap.clear();
    }




}
于 2012-07-12T09:28:26.853 に答える
2

私が考えていたことの非常に迅速な実装。

ChangedRecentlyTOオブジェクトにプロパティがあると仮定しnameます。

private List<ChangedRecentlyTO> groupRecords(List<ChangedRecentlyTO> toList) {

    Map<String, ChangedRecentlyTO> uniqueMap = new HashMap<String, ChangedRecentlyTO>();

    for(ChangedRecentlyTO to : toList) {
        if (uniqueMap.containsKey(to.getName())) {
            if (uniqueMap.get(to.getName()).getTimeChanged().before(to.getTimeChanged())) {
                uniqueMap.put(to.getName(), to);
            }
        } else {
            uniqueMap.put(to.getName(), to);
        }
    }
    return (List<ChangedRecentlyTO>) uniqueMap.values();
}

結局のところ、オーバーライドhashcodeequals.

于 2012-07-12T10:17:59.307 に答える
2

Set以降を使用しない理由:

new ArrayList(set);
于 2012-07-12T08:53:54.103 に答える
1

私が提案することは、Comparable インターフェイスをComparable実装してクラスを作成します。次に、オブジェクトの時間が最近の場合は名前と時間に基づいてそれらを比較し、1を返すか、そうでない場合は0(等しい場合)または-1を返します。この機能を取得したら、HashMapクラスを拡張できますメソッドをオーバーライドします。comparetTo()put

o1.compareTo(o2) > 0 then simply overwrite the object with latest one. 

@Lopina コードにロジックを追加する

public class MyHashMap extends HashMap<String, MyClass>{
private Map<String, MyClass> timeMap;

public MyHashMap() {
    this.timeMap = new HashMap<String, MyClass>();
}

public MyClass put(String key, MyClass value) {

    MyClass obj;
    if (isNewer(key, value)) {
        System.out.println("count");
        obj=this.timeMap.put(key, value);
    }else{
        obj=value;
    }
    return obj;
}

private boolean isNewer(String key, MyClass value) {

    if(this.timeMap.get(key)==null ||( key.equals(value.getName()))&& (this.timeMap.get(key).compareTo(value))<0)
        return true;
    else
        return false;
}

@Override
public int size() {

    return this.timeMap.size();
}

@Override
public MyClass get(Object key) {

    return this.timeMap.get(key);
}
}

MyClass ではcompareTo、以下のように同等のインターフェイスとオーバーライド メソッドを実装します。

@Override
public int compareTo(MyClass o) {

    return this.getTime().compareTo(o.getTime());
}
于 2012-07-12T09:11:21.713 に答える
1

クラスにインターフェイスを実装させ、Comparable関心のあるタイムスタンプを比較チェックさせることができます。その後、並べ替えて (たとえば、すべての要素を a にTreeSet入れる)、それらがまだ存在しない場合にのみ、それらを 1 つずつ取り出します。 . このようなもの:

public void removeDuplicates(List<MyObject> list){
    SortedSet<MyObject> sortedSet = new TreeSet<MyObject>();
    sortedSet.addAll(list);

    //Now clear the list, and start adding them again
    list.clear();
    for(MyObject obj : sortedSet){
        if(!list.contains(obj) {
             list.add(obj);
        } 
    }
    return list;
}

ただし、これは異なるタイムスタンプを持つ 2 つのオブジェクトが等しくない場合にのみ機能します。(equals()言葉の意味で

于 2012-07-12T09:16:16.347 に答える