最快的方法来设置数组的所有值?
我有一个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; }
这是完全相同的过程,这表明可能没有更好的方法来做到这一点。
无论如何,build议fill
+1的人 – 你们都是对的,谢谢。
尝试Arrays.fill(c, f)
: Arrays javadoc
作为另一种select和后代,我最近正在研究这个问题,发现这篇文章提供了一个解决scheme,通过将一些工作交给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; } for (int i = 1; i < len; i += i) { System.arraycopy(array, 0, array, i, ((len - i) < i) ? (len - i) : i); } }
该解决scheme取自R. Dimpsey,R. Arora,K. Kuiper的IBM研究论文“Java服务器性能:构build高效,可扩展的Jvms的案例研究” 。
简单的解释
正如注释所示,这将目标数组的索引0设置为您的值,然后使用System类复制一个对象,即索引0处的索引到索引1,然后将这两个对象(索引0和1)复制到2和3,然后那四个对象(0,1,2和3)分成4,5,6和7等等…
效率
在一个快速的运行过程中,抓住System.nanoTime()
之前和之后计算一个持续时间,我想出了: –
- 这个方法: 332,617 – 390,262 (10次testing中“最高 – 最低”)
-
Float[] n = new Float[array.length]; //Fill with null
Float[] n = new Float[array.length]; //Fill with null
:666,650 - 循环设置: 3,743,488 – 9,767,744 (10次testing中“最高 – 最低”)
-
Arrays.fill
: 12,539,336
使用Arrays.fill
char f = '+'; char [] c = new char [50]; Arrays.fill(c, f)
Java程序员的常见问题B部分第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); }
这基本上使log2(array.length)调用System.arraycopy希望利用优化的memcpy实现。
然而,这种技术仍然需要现代Java JIT,如Oracle / Android JIT?
如果你有另一个字符数组char[] b
并且你想用b
replacec
,你可以使用c=b.clone();
。
System.arraycopy是我的答案。 请让我知道有没有更好的方法。 谢谢
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秒
arrays的2循环需要133536纳秒。
System.arraycopy循环需要22070纳秒。
一轮Arrays.fill需要9777纳秒。
两轮Arrays.fill需要93028纳秒。
12点33分38秒
arrays的2循环需要133816纳秒。
System.arraycopy循环需要22070纳秒。
一轮Arrays.fill需要17042纳秒。
两轮Arrays.fill需要95263纳秒。
12点33分51秒
arrays的2循环需要199187纳秒。
System.arraycopy循环需要44140纳秒。
一轮Arrays.fill需要19555纳秒。
两轮Arrays.fill需要449219纳秒。
12时34分16秒
arrays的2循环需要199467纳秒。
System.arraycopy循环需要42464纳秒。
一轮Arrays.fill需要17600纳秒。
两轮Arrays.fill需要170971纳秒。
12时34分26秒
arrays的2循环需要198907纳秒。
System.arraycopy循环需要24584纳秒。
一轮Arrays.fill需要10616纳秒。
两轮Arrays.fill需要94426纳秒。
请参阅Arrays.fill方法:
char f = '+'; char [] c = new char [50]; Arrays.fill(c, f);
Arrays.fill
可能适合您的需求
Arrays.fill(myArray, 'c');
Arrays.fill
虽然这很可能是在后台执行循环,因此不是比你有什么效率(除了节省的代码行)。 如果您真的关心效率,请尝试以下方法:
int size = 50; char[] array = new char[size]; for (int i=0; i<size; i++){ array[i] = 'c'; }
注意,上面的每个迭代都不会调用array.size()。
/** * 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
。)
你可以使用arraycopy
但这取决于你是否可以预定义源数组,你是否每次都需要填充不同的字符,或者是用相同的字符重复填充数组?
很明显,填充的长度很重要 – 要么你需要一个比所有可能的目的地都要大的源,要么你需要一个循环来重复地对一个数据块进行arrays拷贝,直到目的地已满为止。
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);
Arrays.fill是通用的最佳select。 如果你需要填写大型的数组,但最新的idk 1.8 u102,有一个更快的方式,利用System.arraycopy。 你可以看看这个替代的Arrays.fill实现:
根据JMH基准 ,对于大型arrays(1000 +),您可以获得近2倍的性能提升
无论如何,这些实现只能在需要的地方使用。 JDKs Arrays.fill应该是首选。