74

この質問に似た他の質問をいくつか見ましたが、問題を解決するものを実際に見つけることができませんでした。

私の使用例はこれです: ユーザーは最初に項目のリスト (listA) を持っています。彼らはアイテムを並べ替え、その順序 (listB) を保持したいと考えていますが、制限によりバックエンドで順序を保持できないため、取得後に listA をソートする必要があります。

基本的に、2 つの ArrayLists (listA と listB) があります。1 つは特定のリスト順 (listB) で、もう 1 つはアイテムのリスト (listA) です。listB に基づいて listA をソートしたい。

4

22 に答える 22

74
Collections.sort(listB, new Comparator<Item>() {
    public int compare(Item left, Item right) {
        return Integer.compare(listA.indexOf(left), listA.indexOf(right));
    }
});

ただし、これは非常に非効率的です。おそらくMap<Item, Integer>from listA を作成して、アイテムの位置をより高速に検索する必要があります。

Guava には、それを行うためのすぐに使用できるコンパレーターがあります。Ordering.explicit()

于 2013-08-08T15:27:05.187 に答える
7

これは、時間の複雑さを2nだけ増加させますが、必要なことを達成するソリューションです。また、並べ替えに使用する他のリストが均一に Comparable でRある限り、並べ替えたいList に Comparable 要素が含まれていてもかまいません。L

public class HeavyPair<L extends Comparable<L>, R> implements Comparable<HeavyPair<L, ?>> {
    public final L left;
    public final R right;

    public HeavyPair(L left, R right) {
        this.left = left;
        this.right = right;
    }

    public compareTo(HeavyPair<L, ?> o) {
        return this.left.compareTo(o.left);
    }

    public static <L extends Comparable<L>, R> List<R> sort(List<L> weights, List<R> toSort) {
        assert(weights.size() == toSort.size());
        List<R> output = new ArrayList<>(toSort.size());
        List<HeavyPair<L, R>> workHorse = new ArrayList<>(toSort.size());
        for(int i = 0; i < toSort.size(); i++) {
            workHorse.add(new HeavyPair(weights.get(i), toSort.get(i)))
        }
        Collections.sort(workHorse);
        for(int i = 0; i < workHorse.size(); i++) {
            output.add(workHorse.get(i).right);
        }
        return output;
    }
}

ただし、このコードの作成中に使用したひどい慣行をお許しください。私は急いでいました。

電話するだけHeavyPair.sort(listB, listA);

編集:この行を修正しましたreturn this.left.compareTo(o.left);。今では実際に動作します。

于 2014-02-13T15:29:11.233 に答える
2

リストを並べ替えてから、最初の配列リストに正確に加えられた変更に従って別のリストに変更を加える方法の例を次に示します。このトリックは決して失敗せず、リスト内のアイテム間のマッピングを確実にします。このトリックを使用するには、両方のリストのサイズが同じでなければなりません。

    ArrayList<String> listA = new ArrayList<String>();
    ArrayList<String> listB = new ArrayList<String>();
    int j = 0;
    // list of returns of the compare method which will be used to manipulate
    // the another comparator according to the sorting of previous listA
    ArrayList<Integer> sortingMethodReturns = new ArrayList<Integer>();

    public void addItemstoLists() {
        listA.add("Value of Z");
        listA.add("Value of C");
        listA.add("Value of F");
        listA.add("Value of A");
        listA.add("Value of Y");

        listB.add("this is the value of Z");
        listB.add("this is the value off C");
        listB.add("this is the value off F");
        listB.add("this is the value off A");
        listB.add("this is the value off Y");

        Collections.sort(listA, new Comparator<String>() {

            @Override
            public int compare(String lhs, String rhs) {
                // TODO Auto-generated method stub
                int returning = lhs.compareTo(rhs);
                sortingMethodReturns.add(returning);
                return returning;
            }

        });
        // now sort the list B according to the changes made with the order of
        // items in listA
        Collections.sort(listB, new Comparator<String>() {

            @Override
            public int compare(String lhs, String rhs) {
                // TODO Auto-generated method stub

                // comparator method will sort the second list also according to
                // the changes made with list a
                int returning = sortingMethodReturns.get(j);
                j++;
                return returning;
            }

        });

    }
于 2015-04-13T12:49:09.330 に答える
1

これを行う 1 つの方法は、listB をループして、listA にアイテムが含まれている場合は一時リストにアイテムを追加することです。

List<?> tempList = new ArrayList<?>();
for(Object o : listB) {
    if(listA.contains(o)) {
        tempList.add(o);
    }
}
listA.removeAll(listB);
tempList.addAll(listA);
return tempList;
于 2013-08-08T15:25:54.673 に答える
1

あなたが望むものを完全に明確にするわけではありませんが、これが状況である場合: A:[c,b,a] B:[2,1,0]

そして、それらの両方をロードしてから生成したい: C:[a,b,c]

じゃあ多分これ?

List c = new ArrayList(b.size());
for(int i=0;i<b.size();i++) {
  c.set(b.get(i),a.get(i));
}

それには余分なコピーが必要ですが、それを適切な場所に置くのは効率がはるかに悪く、あらゆる種類が明確ではないと思います:

for(int i=0;i<b.size();i++){
    int from = b.get(i);
    if(from == i) continue;
    T tmp = a.get(i);
    a.set(i,a.get(from));
    a.set(from,tmp);
    b.set(b.lastIndexOf(i),from); 
}

私もテストしなかったことに注意してください。おそらくサインが反転しました。

于 2013-08-10T13:56:03.360 に答える
1

設定に応じて機能する可能性のある別のソリューションは、インスタンスを listB に格納するのではなく、listA のインデックスを格納することです。これは、次のように listA をカスタムのソート済みリスト内にラップすることで実行できます。

public static class SortedDependingList<E> extends AbstractList<E> implements List<E>{
    private final List<E> dependingList;
    private final List<Integer> indices;

    public SortedDependingList(List<E> dependingList) {
        super();
        this.dependingList = dependingList;
        indices = new ArrayList<>();
    }

    @Override
    public boolean add(E e) {
        int index = dependingList.indexOf(e);
        if (index != -1) {
            return addSorted(index);
        }
        return false;
    }

    /**
     * Adds to this list the element of the depending list at the given
     * original index.
     * @param index The index of the element to add.
     * 
     */
    public boolean addByIndex(int index){
        if (index < 0 || index >= this.dependingList.size()) {
            throw new IllegalArgumentException();
        }
        return addSorted(index);
    }

    /**
     * Returns true if this list contains the element at the
     * index of the depending list.
     */
    public boolean containsIndex(int index){
        int i = Collections.binarySearch(indices, index);
        return i >= 0;
    }

    private boolean addSorted(int index){
        int insertIndex = Collections.binarySearch(indices, index);
        if (insertIndex < 0){
            insertIndex = -insertIndex-1;
            this.indices.add(insertIndex, index);
            return true;
        }
        return false;
    }

    @Override
    public E get(int index) {
        return dependingList.get(indices.get(index));
    }

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

次に、このカスタム リストを次のように使用できます。

public static void main(String[] args) {
    class SomeClass{
        int index;
        public SomeClass(int index) {
            super();
            this.index = index;
        }
        @Override
        public String toString() {
            return ""+index;
        }
    }

    List<SomeClass> listA = new ArrayList<>();
    for (int i = 0; i < 100; i++) {
        listA.add(new SomeClass(i));
    }
    SortedDependingList<SomeClass> listB = new SortedDependingList<>(listA);
    Random rand = new Random();

    // add elements by index:
    for (int i = 0; i < 5; i++) {
        int index = rand.nextInt(listA.size());
        listB.addByIndex(index);
    }

    System.out.println(listB);

    // add elements by identity:
    for (int i = 0; i < 5; i++) {
        int index = rand.nextInt(listA.size());
        SomeClass o = listA.get(index);
        listB.add(o);
    }
    System.out.println(listB);      
}

もちろん、このカスタム リストは、元のリストの要素が変更されない限り有効です。変更が可能な場合は、何らかの形で元のリストへの変更をリッスンし、カスタム リスト内のインデックスを更新する必要があります。

また、SortedDependingList は現在、listA からの要素を 2 回追加することを許可していないことに注意してください。この点では、実際には listA からの要素のセットのように機能します。これは通常、このような設定で必要なものだからです。

SortedDependingList に何かを追加するための推奨される方法は、要素のインデックスを既に知っていて、それを sortedList.addByIndex(index); を呼び出して追加することです。

于 2014-02-08T07:02:22.163 に答える
1
List<String> listA;
Comparator<B> comparator = Comparator.comparing(e -> listA.indexOf(e.getValue()));
//call your comparator inside your list to be sorted
listB.stream().sorted(comparator)..
于 2020-06-08T21:55:49.013 に答える
0

これを試して。Objects以下のコードは、特定のタイプを示していないため、listA がリストであるシナリオの一般的な目的です。

Object[] orderedArray = new Object[listA.size()];

for(int index = 0; index < listB.size(); index ++){
    int position = listB.get(index); //this may have to be cast as an int
    orderedArray[position] = listA.get(index);
}
//if you receive UnsupportedOperationException when running listA.clear()
//you should replace the line with listA = new List<Object>() 
//using your actual implementation of the List interface
listA.clear(); 
listA.addAll(orderedArray);
于 2014-02-13T15:24:09.073 に答える
0

IMO、何か他のものを永続化する必要があります。完全なリストBではないかもしれませんが、何か. ユーザーが変更したアイテムのインデックスだけかもしれません。

于 2014-02-11T19:47:01.587 に答える
0

Tim Herold が書いたように、オブジェクト参照が同じでなければならない場合は、次のいずれかの方法で listB を listA にコピーできます。

listA = new ArrayList(listB);

または、listA が参照する List を変更したくない場合は、次のようにします。

listA.clear();
listA.addAll(listB);

参照が同じではなく、listA と listB のオブジェクト間に同等の関係がある場合は、listB でComparatorオブジェクトを検索し、listB のインデックスをソート キーとして使用するカスタムを使用して、listA をソートできます。ブルート フォースで listB を検索する単純な実装は、パフォーマンスの面では最適ではありませんが、機能的には十分です。

于 2013-08-08T15:26:41.513 に答える
-2

Java には、リストまたは配列のソートに役立つ一連のクラスがあります。以下の例のほとんどはリストを使用していますが、配列にも同じ概念を適用できます。例でこれを示します。

整数のリストを作成することでこれを使用し、Collections.sort() を使用してこれらをソートできます。Collections (Java Doc) クラス (Java Collection Framework の一部) は、リストやセットなどのコレクションを操作するときに使用できる静的メソッドのリストを提供します。簡単に言えば、次の例に示すように、 java.util.Collections.sort(the list) を呼び出すだけでリストをソートできます。

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class example {
  public static void main(String[] args) {
    List<Integer> ints = new ArrayList<Integer>();
    ints.add(4);
    ints.add(3);
    ints.add(7);
    ints.add(5);
    Collections.sort(ints);
    System.out.println(ints);
  }
}

上記のクラスは 4 つの整数のリストを作成し、コレクションの sort メソッドを使用して、ソート アルゴリズムを気にすることなくこのリストを (1 行のコードで) ソートします。

于 2014-02-11T14:08:52.550 に答える