java - 两个 ArrayList/List 对象的排序

标签 java arrays sorting arraylist

例如,我有两个数组转换为ArrayList,即firstName和lastName。我想使用名字对这两个列表进行排序,姓氏将跟随名字。

预期输出:

firstNameList = {Andrew, Johnson, William}
lastNameList = {Wiggins, Beru, Dasovich};

我的初始计划:

import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;

String [] firstName = {William, Johnson, Andrew};
String [] lastName = {Dasovich, Beru, Wiggins};

//Will convert arrays above into list.
List <String> firstNameList= new ArrayList<String>();
List <String> lastNameList= new ArrayList<String>();

//Conversion
Collections.addAll(firstNameList, firstName);
Collections.addAll(lastNameList, lastName);

最佳答案

域名

正如我在评论中所说,我建议使用 Person -POJO绑定(bind)firstNamelastName以语义方式:

class Person {
    public static final String PERSON_TO_STRING_FORMAT = "{f: %s, l: %s}";

    private final String firstName;
    private final String lastName;

    private Person(final String firstName, final String lastName) {
        this.firstName = Objects.requireNonNull(firstName);
        this.lastName = Objects.requireNonNull(lastName);
    }

    public static Person of(final String firstName, final String lastName) {
        return new Person(firstName, lastName);
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    @Override
    public String toString() {
        return String.format(PERSON_TO_STRING_FORMAT, getFirstName(), getLastName());
    }
}

转换两个 String[] firstNameslastNames进入List<Person> ,可以提供一种方法:

    public static List<Person> constructPersons(
            final String[] firstNames,
            final String[] lastNames) {
        if (firstNames.length != lastNames.length) {
            throw new IllegalArgumentException("firstNames and lastNames must have same length");
        }
        return IntStream.range(0, firstNames.length)
                .mapToObj(index -> Person.of(firstNames[index], lastNames[index]))
                .collect(Collectors.toCollection(ArrayList::new));
    }

对该方法的说明:这里,我们使用 collect(Collectors.toCollection(...)) 而不是 collect(Collectors.toList()) 因为我们要对列表进行排序,所以对列表的可变性进行一些控制。

从这里开始有两条通用路线:任一路线都为 Person comparable by public class Person implements Comparable<Person> 或者有人写 Comparator<Person> 。我们将讨论这两种可能性。

<小时/>

挑战

目标是排序Person - 对象。排序的主要标准是人员的名字。如果两个人的名字相同,则应按姓氏排序。名字和姓氏都是 String -对象,应按字典顺序排序,即 String的自然顺序。

<小时/>

解决方案 1:实现 Comparable<Person>Person

实现比较的逻辑很简单:

  1. 比较 firstName两个人使用 equals(...) .
  2. 如果相等,则比较 lastName使用 compareTo(...) 并返回结果。
  3. 否则,比较 firstNamecompareTo(...)并返回结果。

相应的方法将如下所示:

public class Person implements Comparable<Person> {
    ...
    @Override
    public final int compareTo(final Person that) {
        if (Objects.equals(getFirstName(), that.getFirstName())) {
            return getLastName().compareTo(that.getLastName());
        }
        return getFirstName().compareTo(that.getFirstName());
    }
    ...
}

虽然不是绝对必要的,但建议类的自然顺序(即 Comparable 实现)与其 equals(...) 一致。 -执行。由于现在情况并非如此,我建议覆盖 equals(...) hashCode() :

public class Person implements Comparable<Person> {
    ...
    @Override
    public final boolean equals(Object thatObject) {
        if (this == thatObject) {
            return true;
        }
        if (thatObject == null || getClass() != thatObject.getClass()) {
            return false;
        }
        final Person that = (Person) thatObject;
        return Objects.equals(getFirstName(), that.getFirstName()) &&
                Objects.equals(getLastName(), that.getLastName());
    }

    @Override
    public final int hashCode() {
        return Objects.hash(getFirstName(), getLastName());
    }
    ...
}

以下代码演示了如何创建和订购 List<Person>从两个String[] :

final List<Person> persons = constructPersons(
        new String[]{"Clair", "Alice", "Bob", "Alice"},
        new String[]{"Clear", "Wonder", "Builder", "Ace"}
);
Collections.sort(persons);
System.out.println(persons);
<小时/>

解决方案 2:实现 Comparator<Person>

实现挑战部分中给出的排序比较的比较器的传统实现可能如下所示:

class PersonByFirstNameThenByLastNameComparator implements Comparator<Person> {
    public static final PersonByFirstNameThenByLastNameComparator INSTANCE =
            new PersonByFirstNameThenByLastNameComparator();

    private PersonByFirstNameThenByLastNameComparator() {}

    @Override
    public int compare(final Person lhs, final Person rhs) {
        if (Objects.equals(lhs.getFirstName(), rhs.getFirstName())) {
            return lhs.getLastName().compareTo(rhs.getLastName());
        }
        return lhs.getFirstName().compareTo(rhs.getFirstName());
    }
}

示例调用可能如下所示:

final List<Person> persons = constructPersons(
        new String[]{"Clair", "Alice", "Bob", "Alice"},
        new String[]{"Clear", "Wonder", "Builder", "Ace"}
);
persons.sort(PersonByFirstNameThenByLastNameComparator.INSTANCE);
System.out.println(persons);

使用 Java 8,构建 Comparator已通过 Comparator.comparing -API 进行了简化。定义Comparator使用 Comparator.comparing 实现挑战部分中给出的顺序-API,我们只需要一行代码:

Comparator.comparing(Person::getFirstName)
    .thenComparing(Person::getLastName)

以下代码演示了 Comparator 是如何实现的用于对 List<Person> 进行排序:

final List<Person> persons = constructPersons(
        new String[]{"Clair", "Alice", "Bob", "Alice"},
        new String[]{"Clear", "Wonder", "Builder", "Ace"}
);
persons.sort(Comparator.comparing(Person::getFirstName)
    .thenComparing(Person::getLastName));
System.out.println(persons);
<小时/>

结束语

一个MRE可在 Ideone 上找到.

我对将名字和姓氏分成两个单独的数组的最初设计决定提出质疑。我选择不包含方法 List<Person> constructPersons(String[] firstNames, String[] lastNames)上课Person因为这只是适配器代码。它应该包含在某个映射器中,但对于 Person 来说不是一个存在的功能。 .

关于java - 两个 ArrayList/List 对象的排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60128651/

相关文章:

javascript - 匹配字谜并推送到数组

php - 自然排序关联数组?

javafx Tableview 按日期排序

java - 在 Java 中解析制表符分隔文本文件时出现错误 ArrayIndexOutOfBoundsException

r - 使用 dplyr 按最后一列对数据框进行排序

java - 如何防止 Eclipse 为每次构建清理 bin 文件夹?

java - Java 中的 Checkstyle 和错误检测器

java - 应该使用什么模式来解析 java 中的 RFC 3339 日期时间字符串

java - ANTLR4语法: evaluation by listener/visitor or better with recursions?

python - 值错误 : object of too small depth for desired array