リミットとカスタムコンパレータを持つ部分ソートコレクション

frizzle:

私はこのようなイメージリストと呼ばれるのArrayListをソートします:

Collections.sort(imageList, new MapComparator(Function.KEY_TIMESTAMP, "dsc"));

これは罰金を動作しますが、今私は、パフォーマンス上の理由から(そう単純にサブリストしません仕事を作成、ArrayListのがソートされていない場合のみ、最新の100枚の画像を表示)制限を設定できるようにしたいです。

マイMapComparatorクラスには、次のようになります。

class MapComparator implements Comparator<HashMap<String, String>>
{
    private final String key;
    private final String order;

    public MapComparator(String key, String order)
    {
        this.key = key;
        this.order = order;
    }

    public int compare(HashMap<String, String> first,
                       HashMap<String, String> second)
    {
        String firstValue = first.get(key);
        String secondValue = second.get(key);
        if(this.order.toLowerCase().contentEquals("asc"))
        {
            return firstValue.compareTo(secondValue);
        }else{
            return secondValue.compareTo(firstValue);
        }

    }
}

誰もが知ってはそれを実装する方法ありますか?前もって感謝します!

スチュアート・マークス:

私はこの種の問題のための正式名称を認識していないんだけど、それが合理的に頻繁に発生し、それは多くの場合、トップのようなものと呼ばれていますKまたはgreatest- k個の問題を。

あなたは確かに最後の要素は、「トップに属している可能性があるため、入力内のすべての要素を処理する必要が  K」セットとあなたはすべての最後の要素を処理してきたまでは知りません。ただし、入力全体をソートする必要はありません。ソートし、次にサブリストを取る、またはストリームと、呼び出すような何かやってsorted()続くlimit()、潜在的にN個の入力要素であるため、非常に高価になることができ、O(NログN)でソートを。しかし、それは単に最大を追跡することにより、O(N)までの時間の複雑さを軽減することが可能ですk個のこれまでのところ、あなたがリストを実行するように見える要素。

:グアバは、まさにこれを行いコレクター持っComparators.greatest(K、コンパレータを)

あなたはグアバを使用しない場合、それは多かれ少なかれ同等だ独自のコレクタを構築するためにあまりにも難しいことではありません。Aは、PriorityQueueこの目的のために非常に便利です。ここでの最初のカットです。

static <T> Collector<T,PriorityQueue<T>,List<T>> topK(int k, Comparator<? super T> comp) {
    return Collector.of(
        () -> new PriorityQueue<>(k+1, comp),
        (pq, t) -> {
            pq.add(t);
            if (pq.size() > k)
                pq.poll();
        },
        (pq1, pq2) -> {
            pq1.addAll(pq2);
            while (pq1.size() > k)
                pq1.poll();
            return pq1;
        },
        pq -> {
            int n = pq.size();
            @SuppressWarnings("unchecked")
            T[] a = (T[])new Object[n];
            while (--n >= 0)
                a[n] = pq.poll();
            return Arrays.asList(a);
        },
        Collector.Characteristics.UNORDERED);
}

これは、使用しPriorityQueueた中間データ構造として。要素が追加されるようにキューを超えた場合に、最小の要素がトリミングされるKをサイズで。結果のリストは、最低から最高にソートされているので、最後には、要素をキューから引き出されており、逆の順序でリストに入れます。

例えば、所与List<Integer>含みます

[920, 203, 880, 321, 181, 623, 496, 576, 854, 323,
 339, 100, 795, 165, 857, 935, 555, 648, 837, 975]

一つは行うことができます

List<Integer> out = input.stream()
                         .collect(topK(5, Comparator.naturalOrder()));

その結果

[979, 936, 890, 875, 831]

余談として、それは単にでコンビネータ方法使用してはるかにマップコンパレータを作成することが可能ですComparatorクラスを。例えば、このようなあなたの入力ルックスをするとします。

    List<Map<String, String>> input =
        List.of(Map.of("name", "map1", "timestamp", "00017"),
                Map.of("name", "map2", "timestamp", "00192"),
                Map.of("name", "map3", "timestamp", "00001"),
                Map.of("name", "map4", "timestamp", "00072"),
                Map.of("name", "map5", "timestamp", "04037"));

することができます簡単に並べ替えるこのようなタイムスタンプでマップ:

    input.stream()
         .sorted(Comparator.comparing(map -> map.get("timestamp")))
         .forEach(System.out::println);

またはリストにそれらを収集、またはソート-in-placeで使用してsort(comparator)、または何でも。あなたは実行してソートを逆にすることができます:

    input.stream()
         .sorted(Comparator.comparing(map -> map.get("timestamp"), Comparator.reverseOrder()))
         .forEach(System.out::println);

後者の出力は、次のようになります。

{name=map5, timestamp=04037}
{name=map2, timestamp=00192}
{name=map4, timestamp=00072}
{name=map1, timestamp=00017}
{name=map3, timestamp=00001}

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=210110&siteId=1