【问题标题】:Convert 3 arrays into 1 object array using Streams使用 Streams 将 3 个数组转换为 1 个对象数组
【发布时间】:2020-09-09 15:53:39
【问题描述】:

假设我有以下三个数组:

int r[] = {255,255,255};
int g[] = {0,0,0};
int b[] = {255,255,255};

所有数组长度相同

我想将它们转换成 Color 类型的对象数组:

public class Color {
   int r,g,b;

   public Color(int r, int g, int b) {
        this.r = r;
        this.g = g;
        this.b = b;
   }

}

Color[] arr = new Color[3];

每个索引将包含来自 3 个数组的同一索引的 r、g、b。例如,假设Color[1] = new Color(r[1],g[1],b[1]);

如何使用 Java Streams 做到这一点?

代码的for循环变体是:

Color arr[] = new Color[r.length];

for(int i=0;i<r.length;i++) {
    Color c = new Color(r[i],g[i],b[i]);
    arr[i] = c;
}

有没有办法使用流来做到这一点?

【问题讨论】:

  • 您真正需要的是zip 流上的操作,was considered but proved impractical 因为并行和潜在无限流的复杂性。使用流而不是 for 循环并没有太大的优势;循环更高效,可读性更强。
  • @chrylis-cautiouslyoptimistic- 我不了解你,但 Ousmane D 的回答非常好。
  • @chrylis-cautiouslyoptimistic- 即使有 zip 用于原始类型甚至对象类型......我认为它不会比任何建议的更好解决这种特定类型的问题主要是因为zip 一次对 两个源 进行操作,正如您在 OPs 中看到的那样,理想情况下,您可以在单个函数中对所有源进行操作的解决方案是好多了。
  • @chrylis-cautiouslyoptimistic-of-of-course 如果对 三个 源或更多源有 zip 操作(对于原语),那么这肯定是我的 OP手头的问题! :)。但是是的,我同意 OPs 方法绝对是惯用的 non-functional 方法。

标签: java arrays java-stream


【解决方案1】:

Arrays::setAll

演示:

import java.awt.Color;
import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int r[] = { 255, 255, 255 };
        int g[] = { 0, 0, 0 };
        int b[] = { 255, 255, 255 };
        Color[] arr = new Color[3];

        Arrays.setAll(arr, i -> new Color(r[i], g[i], b[i]));
        System.out.println(Arrays.toString(arr));
    }
}

或者,您可以使用IntStream:range 迭代并填充arr

import java.awt.Color;
import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
       int r[] = { 255, 255, 255 };
       int g[] = { 0, 0, 0 };
       int b[] = { 255, 255, 255 };
       Color[] arr = new Color[3];

       IntStream.range(0, arr.length).forEach(i->arr[i] = new Color(r[i], g[i], b[i]));
    }
}

【讨论】:

  • 好的,setAll 很酷。我不知道已经添加了。
【解决方案2】:

IntStream.range + mapToObj 然后累加到一个数组中:

IntStream.range(0, r.length)
         .mapToObj(i -> new Color(r[i], g[i], b[i]))
         .toArray(Color[]::new);

【讨论】:

    【解决方案3】:

    你可以使用IntStream.range作为索引序列,然后使用map映射到Color对象,最后收集到数组中

    IntStream.range(0,r.length)
             .boxed()
             .map(i->new Color(r[i],g[i],b[i]))
             .toArray(Color[]::new);
    

    【讨论】:

    • 你的答案和 Ousmane D. 的答案有什么区别?
    • 你为什么使用boxed()?为什么有必要?
    • @ng.newbie TBH 差别不大。它们都是有效的,但mapToObj 是此类场景中的惯用方法(即您想要从原始类型映射到对象类型的位置)。基本上是将原语流转换为Stream&lt;T&gt;
    • @OusmaneD。而mapToObj 效率更高,因为.boxed() .map(i-&gt;new Color(r[i], g[i], b[i])) 将首先将所有int 转换为Integer,然后再次将它们拆箱,因为它相当于.boxed() .map((Integer i) -&gt; new Color(r[i.intValue()], g[i.intValue()], b[i.intValue()])).mapToObj(i -&gt; new Color(r[i], g[i], b[i])) 确实是.mapToObj((int i) -&gt; new Color(r[i], g[i], b[i]))
    • 感谢@Holger 的反馈,实际上我的意图是使用mapToObj,但我确实使用mapToObj 回答了另一个问题,然后我的回答不断被否决并建议使用boxed(),你能如果我的理解有误或有更深层次的东西我必须理解,请更正stackoverflow.com/a/61412082/9959152
    猜你喜欢
    • 2019-04-18
    • 2018-05-08
    • 1970-01-01
    • 2021-12-13
    • 1970-01-01
    • 1970-01-01
    • 2019-02-12
    • 2020-06-17
    相关资源
    最近更新 更多