在java中查找两个列表中的公共元素,并将它们添加到列表中的起始位置,使用java8使用第二个列表的剩余元素

问题描述 投票:0回答:2

我有两个包含姓名的列表。第一个列表

l1
selected 个名称,第二个列表
l2
all 个名称。

示例:

List<String> l1 = {"en", "cu", "eu"};
List<String> l2 = {"ch", "cu", "en", "eu", "pe"};

l1
中的所有元素始终存在于
l2
中。

我想获得将所有常用名称放在开头,然后是其余名称的输出,并且我需要将它们按升序排序。 像这样:

output ->  {cu, en, eu, ch, pe};

我正在尝试做的事情已在下面显示,但不知道如何将公共元素放置在起始位置(第二个列表已排序)并将剩余元素放置在公共元素之后

List<String> common = l2.stream().filter(l2::contains).collect(Collectors.toList());
java list sorting stream
2个回答
2
投票

如果我理解正确,您希望通过将第一个列表

l2
中存在的值放在开头来对第二个列表
l1
中的元素进行排序,并且这两部分都应按字母顺序排序。

您需要为此目的定义一个自定义

Comparator
。从 Java 8 开始,创建比较器的推荐方法是使用静态工厂方法,例如
Comparator.comparing()

在实现比较器时,首先我们需要检查第一个列表中是否存在特定值,并根据检查结果对元素进行排序(提醒:

boolean
值的自然排序是
false
->
true
)。由于列表上的
contains()
成本很高(它会在后台对列表进行迭代,因此运行时间为 O(n)),因此将第一个列表中的数据转储到
HashSet
中会提高性能。并针对该集合执行检查。

为了按字母顺序对列表的两个部分进行排序,我们需要通过应用

Comparator.thenComparing()
并提供
Comparator.naturalOrder()
作为参数来链接第二个比较器。

具体实施方式如下:

List<String> l1 = List.of("en", "cu", "eu");
List<String> l2 = List.of("ch", "cu", "en", "eu", "pe");
        
// output ->  {cu,en,eu,cu,pe};
        
Set<String> toCheck = new HashSet<>(l1);
Comparator<String> comparator =
    Comparator.<String,Boolean>comparing(toCheck::contains).reversed()
        .thenComparing(Comparator.naturalOrder());
        
List<String> sorted = l2.stream()
    .sorted(comparator)
    .toList(); // for Java 16 or collect(Collectors.toList())
    
System.out.println(sorted);

输出:

[cu, en, eu, ch, pe]

0
投票
Set<String> selectedNames = Set.copyOf(l1);

List<String> sorted = Stream.concat(
        l1.stream().sorted(),
        l2.stream().filter(Predicate.not(selectedNames::contains)).sorted()
).toList();

这首先将选定的名称复制到

Set
中,以受益于更快的
contains
操作(O(1) 与 O(n))。

从那里开始,它结合了两个元素流。首先,仅对第一个列表中的元素进行排序。其次,仅对第二个列表中不在第一个列表中的元素进行排序。最后,它将组合后的

Stream
转换为
List

© www.soinside.com 2019 - 2024. All rights reserved.