3

假设我有

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

我该怎么做才能将此未排序的列表转换为:

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

(以必须首先出现的已知值开头的列表(此处为“PREFA”和“PREFZ”),其余按字母顺序排序)

我认为番石榴中有一些有用的类可以完成这项工作(排序,谓词......),但我还没有找到解决方案......

4

6 回答 6

3

我会保留单独的列表。

一种用于已知值和未知值。并分别对它们进行排序,当您需要将它们放在一个列表中时,您可以将它们连接起来。

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

注意:这不是最有效的解决方案。这只是一个简单、直接的解决方案,可以完成工作。

我会首先使用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 回答
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 回答
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

你特别提到了番石榴;连同 Sylvain M 的回答,这是另一种方式(更多的是作为学术练习和展示番石榴的灵活性而不是其他任何东西)

// 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())
);

因此,换句话说,按Integer返回的自然顺序排序List.indexOf(),然后打破与对象本身的自然顺序的联系。

乱七八糟,也许,但很有趣。

于 2010-06-24T21:38:49.630 回答