3

私が持っていると仮定すると

final Iterable<String> unsorted = asList("FOO", "BAR", "PREFA", "ZOO", "PREFZ", "PREFOO");

このソートされていないリストをこれに変換するにはどうすればよいですか:

[PREFZ, PREFA, BAR, FOO, PREFOO, ZOO]

(最初に表示されなければならない既知の値 (ここでは「PREFA」と「PREFZ」) で始まり、残りはアルファベット順にソートされたリスト)

仕事をすることができるグアバにはいくつかの便利なクラスがあると思います(順序付け、述語...)が、まだ解決策を見つけていません...

4

6 に答える 6

3

別のリストを保持します。

既知の値と未知の値の 1 つ。そして、それらを別々に並べ替えます.1つのリストでそれらが必要な場合は、それらを連結するだけです.

knownUnsorted.addAll(unsorted.size - 1, unknonwUnsorted);
于 2010-06-24T13:43:10.243 に答える
3

Listに値を入力し、 Collections.sort(...)を使用することをお勧めします。

何かのようなもの

Collections.sort(myList, new FunkyComparator());

これを使用して:

class FunkyComparator implements Comparator {

    private static Map<String,Integer> orderedExceptions =
        new HashMap<String,Integer>(){{ 
            put("PREFZ", Integer.valueOf(1));
            put("PREFA", Integer.valueOf(2));
        }};

    public int compare(Object o1, Object o2) {
        String s1 = (String) o1;
        String s2 = (String) o2;
        Integer i1 = orderedExceptions.get(s1);
        Integer i2 = orderedExceptions.get(s2);

        if (i1 != null && i2 != null) {
            return i1 - i2;
        }
        if (i1 != null) {
            return -1;
        }
        if (i2 != null) {
            return +1;
        }
        return s1.compareTo(s2);
    }
}
于 2010-06-24T13:54:27.210 に答える
2

私は guava lib のファンなので、それを使った解決策を見つけたいと思っていました。それが効率的かどうかはわかりませんが、他のソリューションと同じくらい簡単だと思うかどうかもわかりませんが、ここにあります:

final Iterable<String> all = asList("FOO", "BAR", "PREFA", "ZOO", "PREFOO", "PREFZ");
final List<String> mustAppearFirst = asList("PREFZ", "PREFA");
final Iterable<String> sorted = 
      concat(
            Ordering.explicit(mustAppearFirst).sortedCopy(filter(all, in(mustAppearFirst))),
            Ordering.<String>natural().sortedCopy(filter(all, not(in(mustAppearFirst)))));
于 2010-06-24T15:33:04.563 に答える
2

注:これは最も効率的なソリューションではありません。これは、仕事を成し遂げるシンプルで簡単なソリューションです。

私は最初Collections.sort(list)にリストをソートするために使用します。

次に、既知の項目を削除して、先頭に追加します。

String special = "PREFA";
if (list.remove(special)
    list.add(0, special);

または、前に必要なこれらの値の配列のリストがある場合は、次のようにすることができます。

String[] knownValues = {};
for (String s: knownValues) {
    if (list.remove(s))
        list.add(0, s);
}
于 2010-06-24T13:21:22.240 に答える
1

私も使用Collections.sort(list)しますが、コンパレーターを使用すると思います。コンパレーター内で独自のルールを定義できます。

class MyComparator implements Comparator<String> {

    public int compare(String o1, String o2) {
        // Now you can define the behaviour for your sorting.
        // For example your special cases should always come first, 
        // but if it is not a special case then just use the normal string comparison.

        if (o1.equals(SPECIAL_CASE)) {
            // Do something special
        }
        // etc.
        return o1.compareTo(o2);
    }

}

次に、次のようにして並べ替えます。

Collections.sort(list, new MyComparator());
于 2010-06-24T13:37:09.623 に答える
1

You specifically mentioned guava; along with Sylvain M's answer, here's another way (more as an academic exercise and demonstration of guava's flexibility than anything else)

// List is not efficient here; for large problems, something like SkipList 
// is more suitable
private static final List<String> KNOWN_INDEXES = asList("PREFZ", "PREFA");

private static final Function<Object, Integer> POSITION_IN_KNOWN_INDEXES 
    = new Function<Object, Integer>() {
  public Integer apply(Object in) {
     int index = KNOWN_INDEXES.indexOf(in);
     return index == -1 ? null : index;
  }     
};


...


List<String> values = asList("FOO", "BAR", "PREFA", "ZOO", "PREFZ", "PREFOO");

Collections.sort(values,
  Ordering.natural().nullsLast().onResultOf(POSITION_IN_KNOWN_INDEXES).compound(Ordering.natural())
);

So, in other words, sort on natural order of the Integer returned by List.indexOf(), then break ties with natural order of the object itself.

Messy, perhaps, but fun.

于 2010-06-24T21:38:49.630 に答える