如何在Java中从另一个数组创建子数组?

369

如何从另一个数组中创建子数组?是否有一种方法可以使用第一个数组的索引来获取子数组:

methodName(object array, int start, int end)

我不想过多使用循环,以免使我的程序变慢。

我一直收到这个错误:

找不到符号方法copyOfRange(int[],int,int)

这是我的代码:

import java.util.*;

public class testing 
{
    public static void main(String [] arg) 
    {   
        int[] src = new int[] {1, 2, 3, 4, 5}; 
        int b1[] = Arrays.copyOfRange(src, 0, 2);
    }
}
10个回答

401

您可以使用

JDK > 1.5

Arrays.copyOfRange(Object[] src, int from, int to)

Javadoc

JDK <= 1.5

System.arraycopy(Object[] src, int srcStartIndex, Object[] dest, int dstStartIndex, int lengthOfCopiedIndices); 

Javadoc


4
我遇到了一个问题,就是在Arrays.copyOfRange中没有Object[]。请检查你的导入是否使用了java.util.Arrays。可能会导入不同版本的Arrays,这浪费了我15分钟去检查JRE和JDK的问题。 - NuclearPeon
@NuclearPeon 谢谢!!! 我自己要花很长时间才能想出来。 Eclipse 自动导入了 org.bouncycastle.util.Arrays - Snackoverflow
这实际上是数组的一部分副本。子数组将像子列表一样指向原始数组。更改数组元素不会影响原始数组,而在子数组中会影响。此外,它具有性能影响,因为不仅复制指针,还复制所有元素(对于对象浅拷贝)。 - Gunnar Bernstein

146

Arrays.copyOfRange(..) 是Java 1.6中新增的方法。因此,也许您没有最新版本的Java。如果无法升级,请查看 System.arraycopy(..)


1
@Sami 要么升级到1.6版本,要么参考这个文档:http://download.oracle.com/javase/1.4.2/docs/api/java/lang/System.html - jmj
4
你的JDK是哪个供应商提供的?Sun/Oracle从未发布过4.00.28版本,而Google也无法找到它。 - Peter Lawrey
copyOfRange 如果目标数组越界,会将多余的元素以 null 填充而不是分配更小的数组 :( - Daniil Iaitskov
23
应该在答案中加入这样一句话,即虽然“start-index”是包含的,但“end-index”是排除在外的。 - Yan King Yin
@YanKingYin,你是正确的——这正是我阅读评论的原因 :) - Ben Kushigian

22

是的,它被称为System.arraycopy(Object, int, Object, int, int)

不过无论如何,它仍然会执行某个循环,在 JIT 可以将其优化为类似于REP STOSW 的东西时(在这种情况下,循环在 CPU 内部),才可以避免执行循环。

int[] src = new int[] {1, 2, 3, 4, 5};
int[] dst = new int[3];

System.arraycopy(src, 1, dst, 0, 3); // Copies 2, 3, 4 into dst

16

JDK >= 1.8

我同意以上所有答案。另外,Java 8 Streams 还有一种很好的方式:

int[] subArr = IntStream.range(startInclusive, endExclusive)
                        .map(i -> src[i])
                        .toArray();

这样做的好处是,它可以适用于许多不同类型的 "src" 数组,并有助于改善对流的编写管道操作。

不是特指此问题,但例如,如果源数组为 double[] 并且我们想要对子数组取 average()

double avg = IntStream.range(startInclusive, endExclusive)
                    .mapToDouble(index -> src[index])
                    .average()
                    .getAsDouble();

6
使用流的想法不错。可以使用Stream.of(source).skip(start).limit(count).toArray(Foo[]::new) - Martin

8
使用可从此链接下载的ApacheArrayUtils,您可以轻松使用该方法。
subarray(boolean[] array, int startIndexInclusive, int endIndexExclusive) 

“boolean”只是一个示例,在Java所有基本数据类型中都有对应的方法。

4
int newArrayLength = 30; 

int[] newArray = new int[newArrayLength];

System.arrayCopy(oldArray, 0, newArray, 0, newArray.length);

2

代码是正确的,所以我猜测您正在使用较旧的JDK。该方法的javadoc说它从1.6版本开始就存在了。在命令行中输入:

java -version

我猜测您没有运行1.6版本


1

如果你正在使用 Java 1.6 版本之前的版本,请改用 System.arraycopy(),或升级你的环境。


0

适用于Java >= 1.8

Arrays.stream(array, incIndex, exclusiveIndex)

0
OP说他们不想要一个for循环,但如果有人需要的话:
int[] subArr = new int[end - start];

for (int i = 0; i < end - start; i++){
    subArr[i] = sourceArr[i + start];
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接