当前位置: 首页 > 面试题库 >

将列表沿元素拆分为子列表

汪正卿
2023-03-14
问题内容

我有这个清单(List<String>):

["a", "b", null, "c", null, "d", "e"]

我想要这样的东西:

[["a", "b"], ["c"], ["d", "e"]]

换句话说,我想使用null值作为分隔符将列表拆分为子列表,以获得列表列表(List<List<String>>)。我正在寻找Java
8解决方案。我已经尝试过,Collectors.partitioningBy但是我不确定这是我要找的东西。谢谢!


问题答案:

我目前想出的唯一解决方案是实现自己的自定义收集器。

在阅读解决方案之前,我想添加一些有关此的注释。我将这个问题更多地当作编程练习,我不确定是否可以使用并行流来完成。

因此,您必须意识到,如果 并行* 运行管道,它将 无声地中断*

不是 理想的行为,应该 避免 。这就是为什么我在组合器部分(而不是(l1, l2) -> {l1.addAll(l2); return l1;})中引发异常,因为在组合两个列表时会并行使用它,以便您有一个异常而不是错误的结果。

同样,由于列表复制,这种方法也不是很有效(尽管它使用本机方法来复制基础数组)。

因此,这是收集器的实现:

private static Collector<String, List<List<String>>, List<List<String>>> splitBySeparator(Predicate<String> sep) {
    final List<String> current = new ArrayList<>();
    return Collector.of(() -> new ArrayList<List<String>>(),
        (l, elem) -> {
            if (sep.test(elem)) {
                l.add(new ArrayList<>(current));
                current.clear();
            }
            else {
                current.add(elem);
            }
        },
        (l1, l2) -> {
            throw new RuntimeException("Should not run this in parallel");
        },
        l -> {
            if (current.size() != 0) {
                l.add(current);
                return l;
            }
        );
}

以及如何使用它:

List<List<String>> ll = list.stream().collect(splitBySeparator(Objects::isNull));

输出:

[[a, b], [c], [d, e]]

当JoopEggen的答案出炉时,看来可以并行完成(为此感谢他!)。这样,它将自定义收集器实现简化为:

private static Collector<String, List<List<String>>, List<List<String>>> splitBySeparator(Predicate<String> sep) {
    return Collector.of(() -> new ArrayList<List<String>>(Arrays.asList(new ArrayList<>())),
                        (l, elem) -> {if(sep.test(elem)){l.add(new ArrayList<>());} else l.get(l.size()-1).add(elem);},
                        (l1, l2) -> {l1.get(l1.size() - 1).addAll(l2.remove(0)); l1.addAll(l2); return l1;});
}

这使有关并行性的段落过时了,但是我将其保留下来,因为它可以很好地提醒您。

请注意,Stream API并不总是可以替代。有些任务使用流更容易且更适合,有些则不是。对于您的情况,您还可以为此创建一个实用程序方法

private static <T> List<List<T>> splitBySeparator(List<T> list, Predicate<? super T> predicate) {
    final List<List<T>> finalList = new ArrayList<>();
    int fromIndex = 0;
    int toIndex = 0;
    for(T elem : list) {
        if(predicate.test(elem)) {
            finalList.add(list.subList(fromIndex, toIndex));
            fromIndex = toIndex + 1;
        }
        toIndex++;
    }
    if(fromIndex != toIndex) {
        finalList.add(list.subList(fromIndex, toIndex));
    }
    return finalList;
}

并称它为List<List<String>> list = splitBySeparator(originalList,Objects::isNull);

可以改进以检查边缘情况。



 类似资料:
  • 问题:如何将列表拆分为两个子列表,其中元素由元素中的选项卡分隔? 上下文:我想读取一个由制表符分隔的文件到Pandas DataFrame中。这些文件看起来像: 列1\t 123 列2\t 列3\t文本 这意味着每行有一列,后面跟着一个选项卡,然后是该列的一个值(有时没有值)。 我的想法是读取文件并将每行保存为列表的元素,然后将列表分成两个,将选项卡前的第一部分作为一个列表,选项卡后的第二部分作为

  • 我有一个对象(Pos)与此模型的集合: 对象列表如下所示: 我想按beforeChangement或afterChangement==”字段拆分此对象列表要使用此格式(列表列表)

  • 问题内容: 我有大量的这种格式的元组列表。每个元组的第二个字段是类别字段。 将其分解为相同类别(A,B,C等)的子列表的最有效方法是什么? 问题答案: 使用itertools.groupby: 产量 或者,要创建一个将每个组作为子列表的列表,可以使用列表理解: to的第二个参数是一个适用于(第一个参数)中每个项目的函数。预期会传回。然后将相同的所有连续项目组合在一起。 operator.itemg

  • 如何将这列列表拆分为两列? 期望的结果:

  • 我有一个包含字典作为元素的单列的。这是以下代码的结果: 我需要将此列拆分为尽可能多的列(我有太多的行和列,并且我无法更改函数),因此输出将是一个包含列,,的数据帧,<代码>功能50。这样做的最佳方式是什么? 一个具体而简单的例子: 但当我尝试用pd.Series或pd.DataFrame包装它时,它说如果数据是标量值,则必须提供索引。提供索引=['feature1','feature2'],我会得

  • 我有一个非常简单的,其中每个单元格都包含一个列表。我想将列表中的每个元素拆分为它自己的列。我可以通过导出值,然后创建一个新的