【问题标题】:Filtering between specific values creating sublists在创建子列表的特定值之间进行过滤
【发布时间】:2021-01-06 16:58:32
【问题描述】:

我有这个清单:

List<String> names= Arrays.asList(new String[]{"Tom", "louis", "martha", "Tom", "john", "Carol", "Tom", "Simon"});

我想创建三个不同的列表,将值放在 Tom word 之间:

"Tom", "louis", "martha";
"Tom", "john", "Carol";
"Tom", "Simon"

我以传统方式处理索引

我的方法很简单;

List<Integer> positionsWithTom = new ArrayList<>();

for(int i=0; i<names.size; i++){
...
positionsWithTom = [0,3,6]
}

然后将值放在不同的列表中

这样做不是很优雅,也许是通过某种方式进行流过滤?

【问题讨论】:

  • 我没有方便的 Java 流 API 语法解决方案,但您的直觉是正确的:原则上,这 可以 使用流优雅地完成。首先,您需要计算"Tom" 个元素的累积数量;对于您的示例,这将为您提供序列 1、1、1、2、2、2、3、3。您可以将这些数字用作groupingBy 收集器的类。 (这一切都可以一次性完成。)
  • 我发布了流式和非流式解决方案。我更喜欢后者。

标签: java list java-stream


【解决方案1】:

我不认为这很容易适用于流。在表达问题陈述方面,流方法也不会比简单的循环更清晰。

只要您不关心子列表的顺序,使用List.lastIndexOfwhile loop 就非常简单。请注意,由于这会破坏原始列表以及这些子列表不重叠的事实,因此子列表不会因原始列表的更改或相互更改而被更改(除非存在对原始列表的引用)。但是,如果这是一个问题,总是可以将sublist 作为参数传递给ArrayList 构造函数。

List<String> names = new ArrayList<>(List.of("Tom", "louis",
        "martha", "Tom", "john", "Carol", "Tom", "Simon"));

List<List<String>> lists = new ArrayList<>();
    
int start;
while ((start = names.lastIndexOf("Tom")) >= 0) {
    ists.add(names.subList(start, names.size()));
    names = names.subList(0, start);
}
    
lists.forEach(System.out::println);

打印

[Tom, Simon]
[Tom, john, Carol]
[Tom, louis, martha]

请注意,可以通过在add 方法中指定0 的索引来颠倒顺序。但由于复制,这对ArrayLists 来说可能很昂贵。 LinkedList 可以减少一些开销。

为了完成,这是我的流解决方案。

  • 首先,根据Tom 的位置,流式传输连续sublists 中的名称。因此,第一个列表包含所有名称,第二个列表包含除最后一个 "Tom" 分组之外的所有名称,依此类推。
  • 然后,对于这些子列表中的每一个,选择最后一个以 Tom 开头的子列表。
  • 并将列表放入集合中。
List<List<String>> result = Stream.iterate(
            names,
            n -> n.size() > 0 && n.lastIndexOf("Tom") >= 0,
            n -> n.subList(0, n.lastIndexOf("Tom")))
        .map(n -> n.subList(n.lastIndexOf("Tom"), n.size()))
        .collect(Collectors.toList());

result.forEach(System.out::println);

打印

[Tom, Simon]
[Tom, john, Carol]
[Tom, louis, martha]

我仍然更喜欢 while 循环解决方案,因为我认为它更简洁。更精通流的人可能会做得更好。

【讨论】:

    【解决方案2】:

    首先,我将值 "Tom" 的元素 ([0, 3, 6]) 的索引收集到 tomindex 列表中。然后我用subList()方法。

    这部分:

    j == tomindex.size() - 1 ? names.subList(tomindex.get(j), names.size())
                            : names.subList(tomindex.get(j), tomindex.get(j + 1))
    

    是不要错过最后一个。 tomindex 的最后一个元素是6,我们需要在索引68 之间获取值,所以我们在末尾使用names.size()

    试试这个:

    List<Integer> tomindex = IntStream.range(0, names.size()).filter(i -> names.get(i).equals("Tom")).boxed()
            .collect(Collectors.toList());
    
    Collection<List<String>> subLists = IntStream.range(0, tomindex.size())
            .mapToObj(j -> j == tomindex.size() - 1 ? names.subList(tomindex.get(j), names.size())
                    : names.subList(tomindex.get(j), tomindex.get(j + 1)))
            .collect(Collectors.toList());
    
    System.out.println(subLists);
    

    输出:

    [[Tom, louis, martha], [Tom, john, Carol], [Tom, Simon]]
    

    【讨论】:

      猜你喜欢
      • 2019-08-23
      • 1970-01-01
      • 2020-03-25
      • 2021-02-07
      • 1970-01-01
      • 1970-01-01
      • 2020-08-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多