我有char []
,我想将每个索引的值设置为相同的char
值。
有明显的方法(迭代):
char f = '+';
char [] c = new char [50];
for(int i = 0; i < c.length; i++){
c[i] = f;
}
但是我想知道是否有一种方法可以利用System.arraycopy
或类似的东西来绕过迭代的需要。有没有办法做到这一点?
编辑:
来自Arrays.java
public static void fill(char[] a, int fromIndex, int toIndex, char val) {
rangeCheck(a.length, fromIndex, toIndex);
for (int i = fromIndex; i < toIndex; i++)
a[i] = val;
}
这是完全相同的过程,这表明可能没有更好的方法来做到这一点。
向所有提出fill
的人提出+1 - 你们都是正确的,谢谢你。
答案 0 :(得分:82)
试试Arrays.fill(c, f)
:Arrays javadoc
答案 1 :(得分:38)
作为另一种选择,对于后人我最近正在研究这篇文章并找到了this文章,该文章提供了一种解决方案,通过将一些工作交给System类来实现更短的循环, (如果您使用的JVM足够智能)可以转换为memset操作: -
/*
* initialize a smaller piece of the array and use the System.arraycopy
* call to fill in the rest of the array in an expanding binary fashion
*/
public static void bytefill(byte[] array, byte value) {
int len = array.length;
if (len > 0){
array[0] = value;
}
//Value of i will be [1, 2, 4, 8, 16, 32, ..., len]
for (int i = 1; i < len; i += i) {
System.arraycopy(array, 0, array, i, ((len - i) < i) ? (len - i) : i);
}
}
此解决方案取自IBM研究论文"Java server performance: A case study of building efficient, scalable Jvms" by R. Dimpsey, R. Arora, K. Kuiper。
简化说明
正如评论建议的那样,这会将目标数组的索引0设置为您的值,然后使用System类复制一个对象,即索引0处的对象到索引1然后是那两个对象(索引0和1) )进入2和3,然后将这四个对象(0,1,2和3)分为4,5,6和7等等......
效率(写作时)
快速浏览,抓住前后System.nanoTime()
并计算我想出的持续时间: -
Float[] n = new Float[array.length]; //Fill with null
:666,650 Arrays.fill
: 12,539,336 JVM和JIT编译
应该注意的是,随着JVM和JIT的发展,这种方法很可能会过时,因为只需使用fill()
,库和运行时优化就可以达到甚至超过这些数字。
在撰写本文时,这是我找到的最快的选择。有人提到现在情况可能并非如此,但我没有检查过。这就是Java的美丽和诅咒。
答案 2 :(得分:10)
使用Arrays.fill
char f = '+';
char [] c = new char [50];
Arrays.fill(c, f)
答案 3 :(得分:6)
Java Programmer's FAQ Part B Sect 6建议:
public static void bytefill(byte[] array, byte value) {
int len = array.length;
if (len > 0)
array[0] = value;
for (int i = 1; i < len; i += i)
System.arraycopy( array, 0, array, i,
((len - i) < i) ? (len - i) : i);
}
这实际上使得对System.arraycopy的log2(array.length)调用有希望利用优化的memcpy实现。
但是,现代Java JIT(如Oracle / Android JIT)仍然需要这种技术吗?
答案 4 :(得分:6)
System.arraycopy是我的答案。请让我知道有没有更好的方法。 THX
private static long[] r1 = new long[64];
private static long[][] r2 = new long[64][64];
/**Proved:
* {@link Arrays#fill(long[], long[])} makes r2 has 64 references to r1 - not the answer;
* {@link Arrays#fill(long[], long)} sometimes slower than deep 2 looping.<br/>
*/
private static void testFillPerformance() {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
System.out.println(sdf.format(new Date()));
Arrays.fill(r1, 0l);
long stamp0 = System.nanoTime();
// Arrays.fill(r2, 0l); -- exception
long stamp1 = System.nanoTime();
// System.out.println(String.format("Arrays.fill takes %s nano-seconds.", stamp1 - stamp0));
stamp0 = System.nanoTime();
for (int i = 0; i < 64; i++) {
for (int j = 0; j < 64; j++)
r2[i][j] = 0l;
}
stamp1 = System.nanoTime();
System.out.println(String.format("Arrays' 2-looping takes %s nano-seconds.", stamp1 - stamp0));
stamp0 = System.nanoTime();
for (int i = 0; i < 64; i++) {
System.arraycopy(r1, 0, r2[i], 0, 64);
}
stamp1 = System.nanoTime();
System.out.println(String.format("System.arraycopy looping takes %s nano-seconds.", stamp1 - stamp0));
stamp0 = System.nanoTime();
Arrays.fill(r2, r1);
stamp1 = System.nanoTime();
System.out.println(String.format("One round Arrays.fill takes %s nano-seconds.", stamp1 - stamp0));
stamp0 = System.nanoTime();
for (int i = 0; i < 64; i++)
Arrays.fill(r2[i], 0l);
stamp1 = System.nanoTime();
System.out.println(String.format("Two rounds Arrays.fill takes %s nano-seconds.", stamp1 - stamp0));
}
12时33分18秒
阵列的2循环需要133536纳秒
System.arraycopy循环需要22070纳秒
一轮Arrays.fill需要9777纳秒
两轮Arrays.fill需要93028纳秒。
12点33分38秒
阵列的2循环需要133816纳秒
System.arraycopy循环需要22070纳秒
一轮Arrays.fill需要17042纳秒
两轮Arrays.fill需要95263纳秒。
12点33分51秒
阵列的2循环需要199187纳秒
System.arraycopy循环需要44140纳秒
一轮Arrays.fill需要19555纳秒
两轮Arrays.fill需要449219纳秒。
12时34分16秒
阵列的2循环需要199467纳秒
System.arraycopy循环需要42464纳秒
一轮Arrays.fill需要17600纳秒
两轮Arrays.fill需要170971纳秒。
12时34分26秒
阵列的2循环需要198907纳秒
System.arraycopy循环需要24584纳秒
一轮Arrays.fill需要10616纳秒
两轮Arrays.fill需要94426纳秒。
答案 5 :(得分:3)
请参阅Arrays.fill方法:
char f = '+';
char [] c = new char [50];
Arrays.fill(c, f);
答案 6 :(得分:3)
如果您有另一个char数组char[] b
并且想要将c
替换为b
,则可以使用c=b.clone();
。
答案 7 :(得分:2)
Arrays.fill(myArray, 'c');
虽然这很可能是在后台进行循环,因此不比你拥有的更有效(除了代码行节省)。如果您真的关心效率,请尝试以下与上述相比:
int size = 50;
char[] array = new char[size];
for (int i=0; i<size; i++){
array[i] = 'c';
}
请注意,上面的内容不会为每次迭代调用array.size()。
答案 8 :(得分:1)
Arrays.fill
可能符合您的需求
答案 9 :(得分:1)
/**
* Assigns the specified char value to each element of the specified array
* of chars.
*
* @param a the array to be filled
* @param val the value to be stored in all elements of the array
*/
public static void fill(char[] a, char val) {
for (int i = 0, len = a.length; i < len; i++)
a[i] = val;
}
这就是Arrays.fill的做法。
(我想你可以进入JNI并使用memset
。)
答案 10 :(得分:1)
从Java-8开始,setAll方法有四种变体,它们使用提供的生成器函数来设置指定数组的所有元素,以计算每个元素。
在这四个重载中,只有三个接受一个声明为这样的基元数组:
如何使用上述方法的例子:
// given an index, set the element at the specified index with the provided value
double [] doubles = new double[50];
Arrays.setAll(doubles, index -> 30D);
// given an index, set the element at the specified index with the provided value
int [] ints = new int[50];
Arrays.setAll(ints, index -> 60);
// given an index, set the element at the specified index with the provided value
long [] longs = new long[50];
Arrays.setAll(longs, index -> 90L);
提供给setAll
方法的函数接收元素索引并返回该索引的值。
你可能想知道字符数组怎么样?
这是setAll
方法的第四次重载发挥作用的地方。由于没有重载消耗一系列字符基元,我们唯一的选择是将字符数组的声明更改为类型Character[]
。
如果将数组类型更改为Character
不合适,那么您可以回退到Arrays.fill方法。
setAll
使用Character[]
方法的示例:
// given an index, set the element at the specified index with the provided value
Character[] character = new Character[50];
Arrays.setAll(characters, index -> '+');
尽管使用Arrays.fill
方法而不是setAll
方法来设置特定的值更简单。
setAll
方法的优点是,您可以将数组的所有元素设置为具有相同的值,也可以生成偶数,奇数或任何其他公式的数组:
e.g。
int[] evenNumbers = new int[10];
Arrays.setAll(evenNumbers, i -> i * 2);
parallelSetAll方法还有几个并行执行的重载,但重要的是要注意传递给parallelSetAll方法的函数必须是无副作用的。
<强>结论强>
如果您的目标只是为数组的每个元素设置特定的值,那么使用Arrays.fill
重载将是最合适的选项。但是,如果您想要更灵活或按需生成元素,那么使用Arrays.setAll
或Arrays.parallelSetAll
(适当时)将是您的选择。
答案 11 :(得分:0)
您可以使用arraycopy
,但这取决于您是否可以预定义源数组, - 每次都需要填充不同的字符,还是使用相同的char重复填充数组?
显然,填充的长度很重要 - 要么你需要一个比所有可能目的地都大的源,要么你需要一个循环来重复数组化一大块数据,直到目标已满。
char f = '+';
char[] c = new char[50];
for (int i = 0; i < c.length; i++)
{
c[i] = f;
}
char[] d = new char[50];
System.arraycopy(c, 0, d, 0, d.length);
答案 12 :(得分:0)
Arrays.fill是通用的最佳选择。 如果您需要填充大型数组,尽管从最新的idk 1.8 u102开始,有一种更快的方式可以利用System.arraycopy。 您可以查看此替代Arrays.fill实施:
根据JMH benchmarks,您可以将大型阵列(1000 +)的性能提升近2倍
在任何情况下,只应在需要时使用这些实现。 JDKs Arrays.fill应该是首选。
答案 13 :(得分:0)
我对罗斯德鲁的回答略有改进。
对于 small 数组,由于与设置System.arraycopy相关的开销,简单循环比System.arraycopy方法更快。因此,最好使用一个简单的循环填充数组的前几个字节,并且只有当填充的数组具有一定的大小时才移动到System.arraycopy。
初始循环的最佳大小当然是JVM特定的和系统特定的。
private static final int SMALL = 16;
public static void arrayFill(byte[] array, byte value) {
int len = array.length;
int lenB = len < SMALL ? len : SMALL;
for (int i = 0; i < lenB; i++) {
array[i] = value;
}
for (int i = SMALL; i < len; i += i) {
System.arraycopy(array, 0, array, i, len < i + i ? len - i : i);
}
}