当前位置: 首页 > 知识库问答 >
问题:

将List转换为数组char[]而不使用System.arraycopy()

曾涵育
2023-03-14

转换/展平列表的简单方法是什么

我知道我可以通过迭代List并使用System.arraycopy来做到这一点,但我想知道是否有更简单的方法使用Java8个流来做到这一点?

可能是这样的,但不必将原语char装箱到Character:

List<char[]> listOfCharArrays = ...

Character[] charArray =
    Stream.of(listOfCharArrays )
        .flatMap(List::stream)
        .toArray(Character[]::new);

共有3个答案

法和安
2023-03-14

正如霍尔格所评论的那样,它可以通过字符串或CharBuffer来完成。

char[] flatten(List<char[]> list) {
    return list.stream()
        .map(CharBuffer::wrap) // Better than String::new
        .collect(Collectors.joining())
        .toCharArray();
}

这要求“完成”数组的开头或结尾没有任何不完整的代理项对字符。

所以将此与:

char[] flatten(List<char[]> list) {
    int totalLength = list.stream().mapToInt(a -> a.length).sum();
    char[] totalArray = new char[totalLength];
    int i = 0;
    for (char[] array : list) {
        System.arraycopy(array, 0, totalArray, i, array.length);
        i += array.length; 
    }
    return totalArray;
}

没有那么大的区别,而且代码更可靠。

或者将整个软件放在不可变的字符串上,而不是放在字符上。

景俊良
2023-03-14

这是我能想到的最具可读性的版本。您可以通过StringBuilder将所有char数组附加到String,然后将其转换为char[]

char[] chars = listOfCharArrays.stream()
    .collect(Collector.of(StringBuilder::new, StringBuilder::append, StringBuilder::append, StringBuilder::toString))
    .toCharArray();

可能比迭代版本慢得多,因为arrayCopy可以复制内存块。

您可以考虑预先计算字符总数以避免StringBuilder数组重新分配,但这种优化和任何其他优化都会侵蚀您从使用流中获得的易读性收益。

int totalSize = listOfCharArrays.stream().mapToInt(arr -> arr.length).sum();
char[] chars = listOfCharArrays.stream()
    .collect(Collector.of(() -> new StringBuilder(totalSize), //... the same

有2个不必要的副本(StringBuilder-

逄征
2023-03-14

我只能想到一件事,那就是使用CharBuffer。出于效率考虑,我总是先计算出正确的大小,然后再进行复制。任何执行多个拷贝和/或字符串处理的解决方案都将效率低下。

当然,我不能保证它不会使用系统。arrayCopy在CharBuffer#put方法中的某个位置。我强烈期望它将使用系统。arrayCopy或类似的内部代码。这可能适用于这里提供的大多数解决方案。

CharBuffer fullBuffer = CharBuffer.allocate(listOfCharArrays.stream().mapToInt(array -> array.length).sum());
listOfCharArrays.forEach(fullBuffer::put);
char[] asCharArray = fullBuffer.array();

如果可以估计最大大小,当然可以通过使用足够大的缓冲区来避免第一次大小计算,但这需要另一份数据副本CharBuffer#array只返回后备数组,这意味着数据只复制一次。

请注意,如果您想使用面向对象的代码,您也可以直接使用CharBuffer。请注意,您需要确保在写入后翻转它,并且CharBuffer是可变的(您可以使用重复asReadOnly方法传递副本-返回的实例引用相同的缓冲区,但具有独立的、可变的“位置”和“限制”字段)。

Buffer和JavaNIO类有点难以理解,但是一旦你理解了它们,你就会从中获得很大的好处,例如当将它们用于CharEncoder或内存映射文件时。

 类似资料:
  • 是否可以将 ?如果是这样 - ? 我目前正在做一个项目,我需要<code>创建一个包含<code>字母表的字符数组。我当前的创建了一个(应该将

  • 问题内容: 我有一个Swift程序,可以与C库互操作。这个C库返回一个内部带有数组的结构,如下所示: 该定义已正确导入到Swift中。但是,该字段被解释为8个元素(类型为)的 元组 ,我不知道如何使用Swift 将其转换为a 。 没有可以接受元组的初始化程序,并且似乎不可能获得指向元组的第一个元素的指针(因为类型可以是异构的,这并不奇怪)。 现在,我最好的主意是创建一个微型C函数,该函数接受指向结

  • 问题内容: 我有这个: 输出: 为什么我在这里出错? 和 错误的含义是什么? 它告诉我什么? 问题答案: 您在这里遇到错误,是因为当您使用接受varargs的函数时,此函数在幕后创建了您在其中传递的对象的新数组。因此,实际上得到 了一个整数数组 。 当您传递整数 数组时,请 在后台创建 一个 整数 数组数组 。这就是为什么您不能通过以下循环对其进行迭代: 尝试像这样更改它: 实际上,您将看到对传递

  • 问题内容: 我希望此代码显示: 问题答案: 在将导致的一个单列表。 如果更改为,它将按预期工作。不知道这是否对您有帮助。

  • 考虑到类有三个字段name(String)、age(int)、salary(double)。 我想创建一个名为键,值为工资的映射(而不是对象本身),如果键不唯一,则使用linkedList保存所有重复键的值。 如何实现这种场景?

  • 我有我想分批处理的编号列表。