java 按自然顺序对对象中的多个字段进行排序

utugiqy6  于 2023-06-20  发布在  Java
关注(0)|答案(3)|浏览(141)

目前我使用的是lamda排序,首先对listID进行排序,然后对ItemName进行排序

Comparator < Item > itemComparator = Comparator.comparing(Item::getListId)
                                               .thenComparing(Item::getItemName);
Collections.sort(itemList, itemComparator);

这在技术上是可行的,但ItemName是字母数字,并按ASCII而不是自然顺序排序,因此不是Item 0,Item 101,Item 28。我要0号28号101号有没有一个简单的方法来做到这一点?
编辑:项目正在从JSON文件获取信息

[{"id": 684, "listId": 1, "name": "Item 684"},
    {"id": 276, "listId": 1, "name": "Item 276"},
    {"id": 808, "listId": 4, "name": "Item 808"},
    {"id": 680, "listId": 3, "name": "Item 680"},
    {"id": 534, "listId": 4, "name": "Item 534"},
    {"id": 906, "listId": 2, "name": "Item 906"},
    {"id": 735, "listId": 1, "name": "Item 735"},
7cwmlq89

7cwmlq891#

根据您添加的JSON,name似乎只是文本“Item”,然后是id。这是数字。比较一下这个。

Comparator<Item> itemComparator = Comparator.comparing(Item::getListId)
        .thenComparing(Item::getId);
Collections.sort(itemList, itemComparator);
dtcbnfnu

dtcbnfnu2#

  • "...因此,项目101、项目28代替项目0。我要0号28号101号有没有一个简单的方法来做到这一点?..."*

您可以从闭包中解析 name 中的数值。

Comparator<Item> comparator
    = Comparator.comparing(Item::getListId)
                .thenComparing(value -> {
                    int indexOf = value.name.indexOf(' ');
                    return Integer.parseInt(value.name.substring(indexOf + 1));
                });
list.sort(comparator);

输出量

[{id=276, listId=1, name='Item 276'},
 {id=684, listId=1, name='Item 684'},
 {id=735, listId=1, name='Item 735'},
 {id=906, listId=2, name='Item 906'},
 {id=680, listId=3, name='Item 680'},
 {id=534, listId=4, name='Item 534'},
 {id=808, listId=4, name='Item 808'}]
vc9ivgsu

vc9ivgsu3#

要实现字母数字项目名称的自然排序,可以修改itemComparator以使用考虑项目名称中的数值的自定义Comparator。下面是一个例子:

Comparator<Item> itemComparator = Comparator.comparing(Item::getListId, Comparator.naturalOrder())
        .thenComparing((item1, item2) -> {
            String itemName1 = item1.getItemName();
            String itemName2 = item2.getItemName();

            // Extract numeric values from item names
            Integer number1 = extractNumber(itemName1);
            Integer number2 = extractNumber(itemName2);

            // Compare numeric values if available
            if (number1 != null && number2 != null) {
                return Integer.compare(number1, number2);
            }

            // Fallback to string comparison
            return itemName1.compareTo(itemName2);
        });

Collections.sort(itemList, itemComparator);

在这个修改后的版本中,我们在thenComparing方法中引入了一个自定义的比较逻辑。extractNumber函数用于从项目名称中提取数值。然后,我们比较这些数值(如果两者都可用)。如果其中一个或两个项名称都不包含数值,则我们回退到使用itemName1.compareTo(itemName2)进行字符串比较。
您还需要单独定义extractNumber方法,可以如下实现:

private Integer extractNumber(String itemName) {
    Matcher matcher = Pattern.compile("\\d+").matcher(itemName);
    if (matcher.find()) {
        return Integer.parseInt(matcher.group());
    }
    return null;
}

extractNumber方法使用正则表达式查找项名称中第一个出现的数值。如果找到匹配项,则返回解析后的整数值;否则,它返回null。
如果您正在寻找一种更简单、可能更快的方法来实现字母数字项目名称的自然排序,您可以使用自定义Comparator和支持自然语言排序的Collator。下面是一个使用Collator的示例:

import java.text.Collator;
import java.util.Comparator;
import java.util.Locale;

// Create a Collator with the desired locale
Collator collator = Collator.getInstance(Locale.getDefault());
collator.setNumericCollation(true);

// Create the itemComparator using the Collator
Comparator<Item> itemComparator = Comparator.comparing(Item::getListId, Comparator.naturalOrder())
        .thenComparing((item1, item2) -> collator.compare(item1.getItemName(), item2.getItemName()));

Collections.sort(itemList, itemComparator);

使用Collator通过利用区域设置定义的自然语言排序规则来简化排序过程。它可能比提取数值和执行自定义比较更有效,尤其是在数据集很大的情况下。
请确保根据您的特定要求调整区域设置(Locale.getDefault()),以确保排序行为符合您预期的语言和文化规范。

相关问题