我有一个char [],我想将每个索引的值设置为相同的char值.
有明显的方法(迭代):
char f = '+';
char [] c = new char [50];
for(int i = 0; i < c.length; i++){
c[i] = f;
}
Run Code Online (Sandbox Code Playgroud)
但是我想知道是否有一种方法可以利用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;
}
Run Code Online (Sandbox Code Playgroud)
这是完全相同的过程,这表明可能没有更好的方法来做到这一点.
无论如何,对所有
建议的人都要+1 fill- 你们都是正确的,谢谢你们.
Ros*_*rew 42
作为另一种选择,对于后人我最近正在研究这个问题并发现这篇文章提供了一个解决方案,通过将一些工作交给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);
}
}
Run Code Online (Sandbox Code Playgroud)
该解决方案取自R. Dimpsey,R.Arora,K.Kuiper撰写的IBM研究论文"Java服务器性能:构建高效,可扩展的Jvms的案例研究".
简化说明
正如评论建议的那样,这会将目标数组的索引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,650Arrays.fill:12,539,336JVM和JIT编译
应该注意的是,随着JVM和JIT的发展,这种方法很可能会过时,因为库和运行时优化可以简单地使用甚至超过这些数字fill().在撰写本文时,这是我找到的最快的选择.有人提到现在情况可能并非如此,但我没有检查过.这是Java的美丽和诅咒.
sou*_*eck 11
使用 Arrays.fill
char f = '+';
char [] c = new char [50];
Arrays.fill(c, f)
Run Code Online (Sandbox Code Playgroud)
小智 7
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);
}
Run Code Online (Sandbox Code Playgroud)
这实际上使得log2(array.length)调用System.arraycopy,希望利用优化的memcpy实现.
但是,现代Java JIT(例如Oracle/Android JIT)仍然需要这种技术吗?
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));
}
Run Code Online (Sandbox Code Playgroud)
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纳秒.
从 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);
Run Code Online (Sandbox Code Playgroud)
提供给该setAll方法的函数接收元素索引并返回该索引的值。
你可能想知道字符数组怎么样?
这是该setAll方法的第四个重载发挥作用的地方。由于没有消耗字符基元数组的重载,我们唯一的选择是将字符数组的声明更改为 type 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 -> '+');
Run Code Online (Sandbox Code Playgroud)
虽然,这是更简单的使用Arrays.fill方法,而不是setAll方法来设置一个特定的值。
该setAll方法的优点是您可以将数组的所有元素设置为具有相同的值或生成偶数、奇数或任何其他公式的数组:
例如
int[] evenNumbers = new int[10];
Arrays.setAll(evenNumbers, i -> i * 2);
Run Code Online (Sandbox Code Playgroud)
并行执行的parallelSetAll方法还有几个重载,但重要的是要注意传递给parallelSetAll方法的函数必须是无副作用的。
结论
如果您的目标只是为数组的每个元素设置一个特定的值,那么使用Arrays.fill重载将是最合适的选择。但是,如果您想要更灵活或按需生成元素,那么使用Arrays.setAllor Arrays.parallelSetAll(在适当的时候)将是您的选择。
| 归档时间: |
|
| 查看次数: |
150253 次 |
| 最近记录: |