【问题标题】:sorting an array List [duplicate]对数组列表进行排序[重复]
【发布时间】:2019-07-01 10:48:34
【问题描述】:

我正在尝试对具有包含整数和字母的字符串的列表数组进行排序,但是当我以常规方式进行排序时,我会得到一些奇怪的输出: 相关代码:

List<String> words = new ArrayList<>();  
words.add("9 hello");
words.add("98 food");
words.add("105 cat");
words.add("2514 human");
words.add("3 pencil");
words.sort(Comparator.reverseOrder());

我期待:

"2514 human"
"105 cat"
"98 food"
"9 hello"
"3 pencil"

但我得到的是这样的:

"98 food"
"9 hello"
"3 pencil"
"2514 human"
"105 cat"

有什么建议吗?

【问题讨论】:

  • 你为什么会期待这样的结果?你要求一个颠倒的字母顺序,这似乎正是你得到的
  • 为什么2514 human应该在105 cat之前?
  • 您正在对文本进行字典序排序。你不是在解释这些数字。 9... 高于 2... 无论之后发生什么。您需要将数字解释为实际数字而不是文本,以便按照您想要的方式对其进行排序。
  • 我猜,你需要一个复合对象并且不是对单词而是对数值进行反向排序
  • 您的值不是整数,而是作为字符串进行比较

标签: java arraylist


【解决方案1】:

我认为您应该创建一个类来表示列表中的元素。 例如:

public class WordCount {
    public static final Comparator<WordCount> BY_COUNT;

    private static final Pattern PATTERN
            = Pattern.compile("\\s*([0-9]+)\\s+(.*)");

    public final int count;
    public final String word;

    public static WordCount parse(String s) {
        Matcher matcher = PATTERN.matcher(s);
        if (!matcher.matches()) {
            throw new IllegalArgumentException("Syntax error: " + s);
        }
        return new WordCount(
                Integer.parseInt(matcher.group(1)), matcher.group(2));
    }

    public WordCount(int count, String word) {
        this.count = count;
        this.word = word;
    }

    @Override
    public String toString() {
        return count + " " + word;
    }

    static {
        BY_COUNT = (WordCount o1, WordCount o2) -> {
            int r = Integer.compare(o1.count, o2.count);
            if (r == 0) {
                r = o1.word.compareTo(o2.word);
            }
            return r;
        };
    }
}

您的代码将变为:

    List<WordCount> words = new ArrayList<>();  
    words.add(WordCount.parse("9 hello"));
    words.add(WordCount.parse("98 food"));
    words.add(WordCount.parse("105 cat"));
    words.add(WordCount.parse("2514 human"));
    words.add(WordCount.parse("3 pencil"));
    words.sort(WordCount.BY_COUNT.reversed());
    words.forEach((wc) -> {
        System.out.println(wc);
    });

结果如下:

2514 human
105 cat
98 food
9 hello
3 pencil

【讨论】:

  • 如果我有大约 10 万个条目,这仍然有效吗?
  • @BLH-Maxx 是吗??
【解决方案2】:

使用 comporator 来解决你的问题

在你的类中添加这段代码

  private static Comparator<String> ORDER_MYLIST = new Comparator<String>() {
            public int compare(String d, String d1) {
                int first = Integer.parseInt(d.split(" ")[0]);//since you have space 
                int second = Integer.parseInt(d1.split(" ")[0]);
                return second - first;//change the order if you want
            }
};

将此代码添加到您的调用函数中

Collections.sort(words, ORDER_MYLIST);

输出:

[2514 human, 105 cat, 98 food, 9 hello, 3 pencil]

会如你所愿。

此链接将使您更好地了解 comporator 的工作原理 https://docs.oracle.com/javase/7/docs/api/java/util/Comparator.html

【讨论】:

  • 这个代码 BLH-Maxx 怎么样?
  • 这是否适用于 100k 条目?
  • 如果数据与您发布的代码相同,它将起作用。
  • 它是一个带有或多或少 100k 行的 redis 数据库,带有一个数字和一个单词
  • 是的,它会工作
【解决方案3】:

您需要有一个自定义比较器来满足您的要求。 Java 8 解决方案:

List<String> words = new ArrayList<>();  
words.add("9 hello");
words.add("98 food");
words.add("105 cat");
words.add("2514 human");
words.add("3 pencil");

// Sort the existing list
words.sort(Comparator.comparing(s -> Integer.parseInt(s.split(" ")[0]), Comparator.reverseOrder()));

// To create new sorted list
List<String> sortedWords = words.stream()
            .sorted(Comparator.comparing(s -> Integer.parseInt(s.split(" ")[0]), Comparator.reverseOrder()))
            .collect(Collectors.toList());

【讨论】:

    【解决方案4】:

    您所得到的完全是字典顺序,因为不是比较数字而是按字母顺序比较数字。 如果您想要其他行为,那么您应该考虑实现您自己的Comparator,您将在其中解析数字。

    【讨论】:

    • 请注意,该术语是字典式。此外,答案看起来更像是评论而不是完整答案。完整的答案可能会提供现成的解决方案,请参阅How to Answer
    • 好的,谢谢你的建议
    • 您确实意识到,当 2 个“h”之间有一个“p”时,您的答案毫无意义。现在说它更像是排序只是取第一个数字并将所有以 1 开头的 b 分组,然后所有以 2 开头的分组,依此类推
    猜你喜欢
    • 2018-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-14
    • 2016-08-04
    • 2021-07-25
    相关资源
    最近更新 更多