列表排序难题

发布于 2024-09-07 01:15:41 字数 342 浏览 8 评论 0 原文

假设我有

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

什么可以将这个未排序的列表转换为:(

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

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

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

Assuming I have

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

What can I do to transform this unsorted list into this:

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

(a list which begin with known values that must appears first (here "PREFA" and "PREFZ") and the rest is alphabetically sorted)

I think there are some usefull classes in guava that can make the job (Ordering, Predicates...), but I have not yet found a solution...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

陌上青苔 2024-09-14 01:15:41

我会保留单独的清单。

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

knownUnsorted.addAll(unsorted.size - 1, unknonwUnsorted);

I would keep separate lists.

One for known values and unknown values. And sort them separately, when you need them in a one list you can just concatenate them.

knownUnsorted.addAll(unsorted.size - 1, unknonwUnsorted);
眼藏柔 2024-09-14 01:15:41

我建议填写 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);
    }
}

I suggest filling List with your values and using Collections.sort(...).

Something like

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

using this:

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);
    }
}
趁微风不噪 2024-09-14 01:15:41

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

我首先使用 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);
}

Note: This is not the most efficient solution. It is just a simple, straightforward solution that gets the job done.

I would first use Collections.sort(list) to sort the list.

Then, I would remove the known items, and add them to the front.

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

Or, if you have a list of array of these values you need in the front you could do:

String[] knownValues = {};
for (String s: knownValues) {
    if (list.remove(s))
        list.add(0, s);
}
旧人 2024-09-14 01:15:41

由于我是番石榴库的粉丝,我想找到一个使用它的解决方案。我不知道它是否有效,也不知道您是否发现它像其他解决方案一样简单,但它在这里:

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

Since I'm a fan of the guava lib, I wanted to find a solution using it. I don't know if it's efficient, neither if you find it as simple as others solution, but it's here:

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)))));
慵挽 2024-09-14 01:15:41

你特别提到了番石榴;与 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())
);

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

也许很混乱,但很有趣。

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.

妞丶爷亲个 2024-09-14 01:15:41

我也会使用 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());

I would also use Collections.sort(list) but I think I would use a Comparator and within the comparator you could define your own rules, e.g.

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);
    }

}

Then sort by doing:

Collections.sort(list, new MyComparator());
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文