【问题标题】:Stream a list of n-integers from a file to create n object array从文件流式传输 n 整数列表以创建 n 对象数组
【发布时间】:2018-05-27 18:36:53
【问题描述】:

假设每个 T 对象都可以实例化为

T tobj = new T(//int value);

因此,要从文件中以空格分隔的整数创建一个 T[ ] 数组,我执行以下操作:

 BufferedReader br;
 FileReader fr;
 int[] arr;
 try{               
        fr = new FileReader(fo); // assume "fo" file name
        br = new BufferedReader(fr);
        arr = Arrays.stream(br.readLine().split("\\s")).mapToInt(Integer::parseInt).toArray();

 }catch(SomeException e){//something else}

T[] tobjarr = new T[arr.length];
    for(int i=0; i<arr.length; ++i)){
        tobjarr[i] = new T(arr[i]);
    }

1.上述方法在时间和空间使用上效率高吗?

2.还有其他方法吗?如果是这样,它与上述方法相比如何?

【问题讨论】:

  • 文件中包含多少个整数?关于空间使用,这不会有效,因为整个文件都加载到内存中(假设它是单行)。
  • 大量。说 > 10^6
  • 我不会说这在今天的标准中很大。您的文件只有几 MB。除非您与数十亿人合作,否则我不会那么担心性能。
  • .toArray()代替.mapToObj(T::new).toArray(T[]::new),你可以跳过临时数组和额外的循环。
  • 然后您需要部分处理数据。只有在你可以用有限的内存处理它们的大块中。

标签: java arrays


【解决方案1】:
T[] array = Arrays.stream(br.readLine().split("\\s"))
    .map(s -> new T(Integer.parseInt(s)))
    .toArray(T[]::new)

编辑:注意到您使用了不同的分隔符

【讨论】:

    【解决方案2】:

    总的来说,您的方法很好。但是,您可以使用单流级联来做到这一点。与您原来的方法相比,这可以为您节省一次迭代

    还要注意,现在我们使用称为 NIO 的 Java 新 I/O API 读取文件。一大优势是它提供了Stream 方法。例如,Files#lines 方法返回文件所有行的流,非常适合您的方法。

    总而言之,这是完整代码:

    String file = ...
    Pattern separator = Pattern.compile("\\s");
    
    try (Stream<String> lines = Files.lines(Paths.get(file))) {
        T[] values = lines                      // Stream<String> lines
            .flatMap(separator::splitAsStream)  // Stream<String> words
            .mapToInt(Integer::parseInt)        // IntStream values
            .mapToObj(T::new)                   // Stream<T> valuesAsT
            .toArray(T[]::new);
    } catch (IOException e) {
        System.out.println("Something went wrong.");
    }
    

    请注意,此代码与您的代码略有不同,因为您的代码将只处理一行并挖掘所有行。如果你不想要它,你可以改变它:

    List<T[]> valuesPerLine = Files.lines(Paths.get(file))  // Stream<String> lines
        .map(separator::splitAsStream)  // Stream<Stream<String>> wordsPerLine
        .map(lineStream -> {
            return lineStream                 // Stream<String> words
                .mapToInt(Integer::parseInt)  // IntStream values
                .mapToObj(T::new)             // Stream<T> valuesAsT
                .toArray(T[]::new);
        })                              // Stream<T[]> valuesPerLine
        .collect(Collectors.toList());
    

    与您的原始方法的主要区别在于,我们可以通过使用 mapToObj(T::new) 轻松将 IntStream 转换为 Stream&lt;T&gt;(或者如果它是常规流而不是 IntStream,则只需 map)通过构造函数的元素。之后,我们使用toArray(T[]::new)Stream&lt;T&gt; 收集到一个数组中。

    【讨论】:

    • 嗯,虽然 NIO 的许多方法抛出 java.io.UncheckedIOException 而不是 java.io.IOException,但 Files#lines 方法似乎也强制你捕获异常,它根据其文档和源代码抛出java.io.IOException。我已经更新了答案并添加了try-catch
    • 如果我的数据源不是无干扰的怎么办?
    • 最好使用try with resources
    • @FedericoPeraltaSchaffner 谢谢,我认为Files#lines 自己会这样做。但显然它没有:Why is Files.lines (and similar Streams) not automatically closed?
    • @magpie Files#lines 内部使用BufferedReader,所以它会同样有效。请参阅source code。优点是它会在错误情况下自动关闭BufferedReader,并附加关闭时发生的任何其他异常,它只是为非常频繁的读取文件需求提供了一个非常紧凑的解决方案。
    猜你喜欢
    • 2021-07-20
    • 1970-01-01
    • 2012-04-29
    • 2020-01-07
    • 2016-09-01
    • 2019-05-16
    • 1970-01-01
    • 2021-01-27
    • 2022-01-05
    相关资源
    最近更新 更多