Fastest way to set all values of an array? - java

I have a char [], and I want to set the value of every index to the same char value.
There is the obvious way to do it (iteration):
char f = '+';
char [] c = new char [50];
for(int i = 0; i < c.length; i++){
c[i] = f;
}
But I was wondering if there's a way that I can utilize System.arraycopy or something equivalent that would bypass the need to iterate. Is there a way to do that?
EDIT :
From 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;
}
This is exactly the same process, which shows that there might not be a better way to do this.
+1 to everyone who suggested fill anyway - you're all correct and thank you.

Try Arrays.fill(c, f) : Arrays javadoc

As another option and for posterity I was looking into this recently and found a solution that allows a much shorter loop by handing some of the work off to the System class, which (if the JVM you're using is smart enough) can be turned into a memset operation:-
/*
* 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);
}
}
This solution was taken from the IBM research paper "Java server performance: A case study of building efficient, scalable Jvms" by R. Dimpsey, R. Arora, K. Kuiper.
Simplified explanation
As the comment suggests, this sets index 0 of the destination array to your value then uses the System class to copy one object i.e. the object at index 0 to index 1 then those two objects (index 0 and 1) into 2 and 3, then those four objects (0,1,2 and 3) into 4,5,6 and 7 and so on...
Efficiency (at the point of writing)
In a quick run through, grabbing the System.nanoTime() before and after and calculating a duration I came up with:-
This method : 332,617 - 390,262 ('highest - lowest' from 10 tests)
Float[] n = new Float[array.length]; //Fill with null : 666,650
Setting via loop : 3,743,488 - 9,767,744 ('highest - lowest' from 10 tests)
Arrays.fill : 12,539,336
The JVM and JIT compilation
It should be noted that as the JVM and JIT evolves, this approach may well become obsolete as library and runtime optimisations could reach or even exceed these numbers simply using fill().
At the time of writing, this was the fastest option I had found. It has been mentioned this might not be the case now but I have not checked. This is the beauty and the curse of Java.

Use Arrays.fill
char f = '+';
char [] c = new char [50];
Arrays.fill(c, f)

Java Programmer's FAQ Part B Sect 6 suggests:
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);
}
This essentially makes log2(array.length) calls to System.arraycopy which hopefully utilizes an optimized memcpy implementation.
However, is this technique still required on modern Java JITs such as the Oracle/Android JIT?

System.arraycopy is my answer. Please let me know is there any better ways. 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
Arrays' 2-looping takes 133536 nano-seconds.
System.arraycopy looping takes 22070 nano-seconds.
One round Arrays.fill takes 9777 nano-seconds.
Two rounds Arrays.fill takes 93028 nano-seconds.
12:33:38
Arrays' 2-looping takes 133816 nano-seconds.
System.arraycopy looping takes 22070 nano-seconds.
One round Arrays.fill takes 17042 nano-seconds.
Two rounds Arrays.fill takes 95263 nano-seconds.
12:33:51
Arrays' 2-looping takes 199187 nano-seconds.
System.arraycopy looping takes 44140 nano-seconds.
One round Arrays.fill takes 19555 nano-seconds.
Two rounds Arrays.fill takes 449219 nano-seconds.
12:34:16
Arrays' 2-looping takes 199467 nano-seconds.
System.arraycopy looping takes 42464 nano-seconds.
One round Arrays.fill takes 17600 nano-seconds.
Two rounds Arrays.fill takes 170971 nano-seconds.
12:34:26
Arrays' 2-looping takes 198907 nano-seconds.
System.arraycopy looping takes 24584 nano-seconds.
One round Arrays.fill takes 10616 nano-seconds.
Two rounds Arrays.fill takes 94426 nano-seconds.

As of Java-8, there are four variants of the setAll method which sets all elements of the specified array, using a provided generator function to compute each element.
Of those four overloads only three of them accept an array of primitives declared as such:
setAll(double[] array, IntToDoubleFunction generator)
setAll(int[] array, IntUnaryOperator generator)
setAll(long[] array, IntToLongFunction generator)
Examples of how to use the aforementioned methods:
// 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);
The function provided to the setAll method receives the element index and returns a value for that index.
you may be wondering how about characters array?
This is where the fourth overload of the setAll method comes into play. As there is no overload that consumes an array of character primitives, the only option we have is to change the declaration of our character array to a type Character[].
If changing the type of the array to Character is not appropriate then you can fall back to the Arrays.fill method.
Example of using the setAll method with Character[]:
// given an index, set the element at the specified index with the provided value
Character[] character = new Character[50];
Arrays.setAll(characters, index -> '+');
Although, it's simpler to use the Arrays.fill method rather than the setAll method to set a specific value.
The setAll method has the advantage that you can either set all the elements of the array to have the same value or generate an array of even numbers, odd numbers or any other formula:
e.g.
int[] evenNumbers = new int[10];
Arrays.setAll(evenNumbers, i -> i * 2);
There's also several overloads of the parallelSetAll method which is executed in parallel, although it's important to note that the function passed to the parallelSetAll method must be side-effect free.
Conclusion
If your goal is simply to set a specific value for each element of the array then using the Arrays.fill overloads would be the most appropriate option. However, if you want to be more flexible or generate elements on demand then using the Arrays.setAll or Arrays.parallelSetAll (when appropriate) would be the option to go for.

I have a minor improvement on Ross Drew's answer.
For a small array, a simple loop is faster than the System.arraycopy approach, because of the overhead associated with setting up System.arraycopy. Therefore, it's better to fill the first few bytes of the array using a simple loop, and only move to System.arraycopy when the filled array has a certain size.
The optimal size of the initial loop will be JVM specific and system specific of course.
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);
}
}

If you have another array of char, char[] b and you want to replace c with b, you can use c=b.clone();.

See Arrays.fill method:
char f = '+';
char [] c = new char [50];
Arrays.fill(c, f);

Arrays.fill might suit your needs

Arrays.fill(myArray, 'c');
Arrays.fill
Although it is quite possible that this is doing the loop in the background and is therefore not any more efficient than what you have (other than the lines of code savings). If you really care about efficiency, try the following in comparison to the above:
int size = 50;
char[] array = new char[size];
for (int i=0; i<size; i++){
array[i] = 'c';
}
Notice that the above doesn't call array.size() for each iteration.

/**
* 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;
}
That's the way Arrays.fill does it.
(I suppose you could drop into JNI and use memset.)

You could use arraycopy but it depends on whether you can predefine the source array, - do you need a different character fill each time, or are you filling arrays repeatedly with the same char?
Clearly the length of the fill matters - either you need a source that is bigger than all possible destinations, or you need a loop to repeatedly arraycopy a chunk of data until the destination is full.
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 is the best option for general purpose use.
If you need to fill large arrays though as of latest idk 1.8 u102, there is a faster way that leverages System.arraycopy.
You can take a look at this alternate Arrays.fill implementation:
According to the JMH benchmarks you can get almost 2x performance boost for large arrays (1000 +)
In any case, these implementations should be used only where needed. JDKs Arrays.fill should be the preferred choice.

Related

Adding all indexes of arrays to one single array

I was wondering if this is the most efficient or even good code practice to add arrays to a single array as far as my knowllage goes its time would be O(n). This is only for practice and I want to do it for int [] not for the code to be changed so it is a List.
static int[] allArrayDirections(int row[], int col [], int diag []) {
int counter = 0;
int allDirectionsInMatrix [] = new int [row.length + col.length + diag.length];
for(int i = 0; i < row.length; i++) {
allDirectionsInMatrix[counter++] = row[i];
}
for(int j = 0; j < col.length; j++) {
allDirectionsInMatrix[counter++] = col[j];
}
for(int i = 0; i < diag.length; i++) {
allDirectionsInMatrix[counter++] = diag[i];
}
return allDirectionsInMatrix;
}
You could compare your linear solution to a sort of unravelled:
Find the longest of the three arrays, take its length as counter boundary
assign the longest array to a new variable first, the other two to second and third – just fiddling with the references so the for looks straightforward
loop once from 0 to the counter boundary
fill your target array in three steps, using the other array's length as offset – unless the smaller arrays are already exhausted, so skip them
This will need some add operation for the offset calculation to write to allDirectionsInMatrix and two greater then checks. Depending on the VM's optimization/ array lengths/ call frequency this might cut it in half.
The single for-loop looks similar to this:
// assuming first.length >= second.length >= third.length;
for(int i=0;i<largestLength;i++) {
allDirectionsInMatrix[i]=first[i];
if (second.length > i)
allDirectionsInMatrix[i+first.length]=second[i];
// I assume when called often enough VM does auto trickery
// with the repeated addition of i and first.length
if (third.length > i)
allDirectionsInMatrix[i+first.length+second.length]=third[i];
}
But this might also break other VM optimizations when treating the arrays independently. So really compare runtime. I'd appreciate to read about your measurements.
Just FYI (and not a reals answer to your question, but maybe interesting for comparison)
One way to concatenate integer arrays (using Streams) would be
int[] a = {1,2,3};
int[] b = {4,5,6,7};
int[] c = IntStream.concat(Arrays.stream(a), Arrays.stream(b)).toArray();
System.out.println(Arrays.toString(c));
(Stream.concat for arrays of other types)

Putting an array into a bigger array

I have an array of terms (terms meaning an object with a coefficient and a degree, represented as for example 1.0x^6). The array that I have right now contains 3 terms:
[1.0x^6, 4.0x^5, 10.0x^0].
My goal is to create a bigger array with these terms, but ALSO with terms with a 0 coefficient that are not represented in my array. That probably was not too clear, so here is basically what I want my new array to look like:
[1.0x^6, 4.0x^5, 0.0x^4, 0.0x^3, 0.0x^2, 0.0x^1, 10.0x^0].
Currently, I am iterating through my original array, and if the degree equals the new array.length - 1, I am setting newArray[i] = array[i], if that makes sense. For example, for the first term and i = 0, the degree is 6, and so if 6 = newArray.length - 1 (which is 6), then newArray[i] = array[i].
The problem, however is that array is smaller than newArray, so I am getting an out of bounds error. Any ideas on how to fix this? Sorry for the long post, thanks!
EDIT: Here is my actual code. Sorry if the explanation was unclear.
int max = 0;
Term temp;
for(int i=0; i<array.length; i++) {
max = i;
for(int j=i; j< array.length; j++) {
if(array[j].getDegree() > array[max].getDegree()) {
max = j;
}
}
temp = array[i];
array[i] = array[max];
array[max] = temp;
}
Above, the array is sorted in terms of descending degree. I want to now have the new array contain the old terms, but also 0x^i for all the i that are not used in my set of terms.
Term[] newArray = new Term[this.degree()+1];
for (int c = 0; c < newArray.length; c++) {
if (array[c].getDegree()==newArray.length-1-c) {
newArray[c] = array[c];
}
else {
newArray[c] = new Term(0, newArray.length-1-c);
}
}
There are issues in my code above, and I can see that now because in that for loop, array[c] is not defined for any c > 2. Eclipse is telling my that I have an out of bounds error.
Arrays have a fixed size. If you want to create a bigger array, you need to know the size beforehand and define it accordingly. Also, it seems that you are going through both the arrays using the same iteration variable.
I assume you are doing something like this:
for(i=0;i<newArray.length;i++){
newArray[i] = array[i]; //size of newArray is bigger than array
}
Then you will always get an array index out of bounds exception because "array" is smaller than "newArray" and you go out of bounds when i>=array.length.
You need to fix your code logic.

Performant way to select N random distinct ints in java?

I currently am looking for the best way so select x unique ints among a range of n ints. It would be like doing Random.nextInt(range) multiple time except it should never select twice the same int.
If it happens that x > n then the result would only contain n ints
I tried to do this myself and I currently have done this based on the Fisher/Yates shuffle:
private static final Random R = new Random();
public static int[] distinctRandoms(int nb, int max) {
int[] all = new int[max];
for (int i = 0; i < all.length; i++) {
all[i] = i;
}
if (max <= nb) {
return all;
}
int index;
int[] result = new int[nb];
for (int j = 0, k = all.length - 1; k > 0 && j < nb; k--, j++) {
index = R.nextInt(k + 1);
result[j] = all[index]; // save element
all[index] = all[k]; // overwrite chosen with last element
}
return result;
}
It works and performance seems good but I can't help thinking there must still be some more performant way to do so and that i'm reinventing the wheel. I thought about doing things differently if nb > (max / 2) (remove elements rather than select elements) but as you can't truncate an array in java you still end up copying all the elements you need.
This method costs alot if nb = max-1
Is there any built in way to randomly select distinct ints efficiently in java ?
Edit 1:
What I mean by performant is time-efficient. I want it to be fast. I'll mostly work with small sets of randoms.
Edit 2:
I tried using shuffle like that but it's much more expensive in terms of time because of all the extra object creation.
public static Integer[] distinctRandoms2(int nb, int max) {
ArrayList<Integer> all = new ArrayList<Integer>(max);
for (int i = 0; i < max; i++) {
all.add(i);
}
if (max <= nb) {
return all.toArray(new Integer[max]);
}
Collections.shuffle(all);
return all.subList(0, nb).toArray(new Integer[nb]);
}
You can use Floyd's algorithm. It is much more efficient than shuffling if the number of elements to be selected is smaller than their range.
private static final Random random = new Random();
/**
* Converts a set of Integer to an array of int.
*/
private static int[] setToArray(Set<Integer> aSet) {
int[] result = new int[aSet.size()];
int index = 0;
for (int number : aSet) {
result[index] = number;
index++;
}
return result;
}
/**
* Generates an array of min(count, maxValue) distinct random ints
* from [0, maxValue - 1] range.
* #param count The number of elements to be generated.
* #param maxValue The upper bound of the range(exclusively).
*/
public static int[] getDistinctRandomNumbers(int count, int maxValue) {
Set<Integer> was = new HashSet<>();
for (int i = Math.max(0, maxValue - count); i < maxValue; i++) {
int curr = i == 0 ? 0 : random.nextInt(i);
if (was.contains(curr))
curr = i;
was.add(curr);
}
return setToArray(was);
}
It has O(count) time and space complexity, where count is number of distinct integers that should be generated.
You can use shuffle method from java.util.Collections class.
Just create list of Integers from 0 to x-1, then call shuffle method on it and take first nb elements.
Using shuffle method has sense when nb is close to max. So it would be good for following pairs of parameters:
nb=70, max=100
nb=900, max=1000
nb=9000, max=10000
but not so good for:
nb=10, max=10^8
nb=100, max=10^9
It would be a good idea to combine above method (using shuffle) with Floyd's algorithm from other answer. Selection of algorithm should be based on ratio nb/max. Border ratio should be chosen carefully.
It depends on what you mean by Performant and Random.
If you really are in need of something that costs O(1) or similar then you could use a Linear feedback shift register or LFSR. It generates a random-like sequence of numbers (i.e. statistically random but theoretically predictable) using a simple XOR operation on the previous number and is thus probably the fastest mechanism possible.
This approach is most appropriate if you want any n-bit number. Limiting the number range by discarding those outside the required range may reduce performance.
If by "small sets of randoms" you mean that max is small, the Collections#shuffle approach is probably as good as you can get.
If max can be arbitrary large but nb is small then using a HashSet may be your best option, although you will have some boxing/unboxign cost. If you want to avoid that cost, you can try using an IntHashSet or a similar primitive specialisation of HashSet.

Getting the largest k elements of a double array

The problem I am facing is this one:
I have an array of doubles from which I want to keep the top k greater values.
I have seen some implementations involving Arrays.sort. For example in this example with relative issue it is suggested to use this approach.
Since I am only interested in the first k elements I have also experimented with MinMaxPriorityQueue. I have created a MinMaxPriorityQueue with a maximumSize:
Of course there is again autoboxing.
Builder<Comparable> builder = MinMaxPriorityQueue.maximumSize(maximumSize);
MinMaxPriorityQueue<Double> top2 = builder.create();
The problem is that the order is the ascending one that it's the opposite of the one I want. So I cannot use it this way.
To state the problem's real parameters my arrays is about 50 elements long and I am interested in up to the top k = 5 elements.
So is there any way to bypass this problem using the second approach? Should I stay with the first one even though I don't really need all elements sorted? Do you know if there is any significant difference in speed performance (I will have to use this in a lot of situations so that's where the speed is needed)? Is there any other solution I could use?
As for the performance, I know I can theoretically check it myself but I am a bit out of time and if someone have any solution I am happy to hear it (or read it anyway).
If you only have like 50 elements, as noted in my comment, just sort it and take the last k elements. It's 2 lines only:
public static double[] largests(double[] arr, int k) {
Arrays.sort(arr);
return Arrays.copyOfRange(arr, arr.length - k, arr.length);
}
This modifies (sorts) the original array. If you want your original array unmodified, you only need +1 line:
public static double[] largests2(double[] arr, int k) {
arr = Arrays.copyOf(arr, arr.length);
Arrays.sort(arr);
return Arrays.copyOfRange(arr, arr.length - k, arr.length);
}
You can use System.arraycopy on a sorted array:
double[] getMaxElements(double[] input, int k) {
double[] temp = Arrays.copyOf(input, input.length);
Arrays.sort(temp); // Sort a copy to keep input as it is since Arrays.sort works in-place.
return Arrays.copyOfRange(temp, temp.length - k, temp.length); // Fetch largest elements
}
For 50 elements, it is much faster to sort an array than to mess with generics and comparables.
I will write up an additional "fast" algorithm...
double[] getMaxElements2(double[] input, int k) {
double[] res = new double[k];
for (int i = 0; i < k; i++) res[i] = Double.NEGATIVE_INFINITY; // Make them as small as possible.
for (int j = 0; j < input.length; j++) // Look at every element
if (res[0] < input[j]) { // Keep the current element
res[0] = input[j];
Arrays.sort(res); // Keep the lowest kept element at res[0]
}
return res;
}
This is O(N*k*log(k)) while the first one is O(N*log(N)).

Java initialize large array with Max value

How can I initialize an array of size 1000 * 1000 * 1000 * 1000 of all Integer.MAXVALUE?
for example, I want to make this int[][][][]dp = new int [1000][1000][1000][1000]; all have max value as later I need to compare a minimum.
I tried
int [] arr = new int arr[N];
Arrays.fill(arr,Integer.MAXVALUE);
but it doesn't work with multidimensional arrays, can anyone help?
You'll have to do this to fill your multi-dimensional array:
for (int i = 0; i < dp.length; i++) {
for (int j = 0; j < dp[i].length; j++) {
for (int k = 0; k < dp[j].length; k++) {
Arrays.fill(dp[i][j][k], Integer.MAX_VALUE);
}
}
}
You won't however be able to initialize new int[1000][1000][1000][1000] unless you have at least 3.64 terabytes of memory. Not to mention how long that would take if you did have that much memory.
You need something very specialized like Colt to generate what is called a Sparse Matrix. You need to alter your logic slightly, instead of testing against a Integer.MAX_VALUE you test to see if something exists at a location ( defaults to ZERO ), if it doesn't then consider it Integer.MAX_VALUE and leave it alone.
This assumes you only insert a fraction of the possible data with values < Integer.MAX_VALUE.
fill will need as arguments the array and the values to fill per dimension. Say fill(array, 0,0,0) or in your case fill(array, maxValue, maxValue, maxValue).
Cheers,

Categories