Fill a 3d array with stream in java - arrays

My current code is like:
double[][][] result = new double[1000][][];
for (int i = 0; i < result.length; i++){
result[i] = somemethod();
}
Now I want to use stream to do the same thing. I did a lot of research, but cannot find an answer to fill the first dimension with the return value of another method.

For your task, the 3D nature of the array is irrelevant. You can replace double[][] with X in your mind and follow the same generic steps, you would do when producing the array X[]:
X[] array = IntStream.range(0, size).mapToObj(i -> somemethod()).toArray(X[]::new);
Using double[][] for X and 1000 for size yields:
double[][][] result
= IntStream.range(0, 1000).mapToObj(i -> somemethod()).toArray(double[][][]::new);
If somemethod() is expensive, but has no interference (so multiple concurrent calls are safe), you can use .parallel() with the stream. You could also use
double[][][] result = new double[1000][][];
Arrays.parallelSetAll(args, i -> somemethod());
in that case.

Related

Scala: filtering an array with filter vs. for each

I have this problem: I want to iterate on the elements of an array that satisfy a certain condition.
The first thing I though is to use the filter method on the original array and then iterates over the resulting elements. But I had some memory usage problem with that, i.e. java heap space.
When a filter is applied on an array, it will instantiate a new array? So it will copy each element?
Is it better to use this approach:
array.filter(<condition>).foreach{ element =>
do something
}
Or the following one?
for(i <- array.indices if <condition>){
do something
}
Moreover, I wrote these two tests:
With for
val size = 10000000
val elements = Array.ofDim[Double](size)
for (i <- elements.indices) {
elements.update(i, math.random)
}
var cont = 0
val n = 0.5
while(true){
cont = 0
for (j <- elements.indices if elements(j) < n) {
cont += 1
}
println(cont)
}
with filter
val size = 10000000
val elements = Array.ofDim[Double](size)
for (i <- elements.indices) {
elements.update(i, math.random)
}
val n = 0.5
while(true){
val valid = elements.filter(x => x < n)
println(valid.size)
}
and I checked the memory usage with VisualVM, it seem that the first solution uses less memory than the second one.
This is the memory used by the first solution
This is the memory used by the second solution
The for expression use the withFilter method rather than filter, which avoids creating the intermediate Array. So either use the for version or use withFilter rather than filter.

Code is not executing the else condition in the inner most loop when matching array to array index by index?

var amazon = activeSpreadsheet.getSheetByName('Amazon');
var lastRow1 = amazon.getLastRow();
var array1 = amazon.getRange('A2:A' + lastRow1).getValues();
var source = activeSpreadsheet.getSheetByName('ProductDetails');
var lastRow2 = source.getLastRow();
var array2 = source.getRange('B2:B' + lastRow2).getValues();
n = 2;
x = 0; // match
z = 0; // non-match
for (var i = 0; i < array2.length; i++){
for (var j = 0; j < array1.length; j++){
if (array2[i] !== array1[j]){
z = z + 1;
}
else {
x = 9999
}
}
newsheet.getRange([n],[5]).setValue(z);
newsheet.getRange([n],[6]).setValue(x);
if (z > x) {
newsheet.getRange([n],[1]).setValue(array2[i]);
n == n++;
z = 0;
x = 0;
}
else if (z < x) {
z = 0;
x = 0;
}
}
My project is written in GAS (google app scripts) which is essentially, for all intents and purposes JS with variation in libraries.
Basically I am grabbing an element in the array2 and passing it through a loop to match to array1. For every time it does not match it adds 1, and when it matches (should only match once if it has any matches) it stores an arbitrary large number (larger than length of array1) and compares them.
As you can see I've written out to display these values and I always get z = 5183 (length of array1) and x = 0 (meaning no non-matches found). Therefore even if something exists in array 2 and 1 it will always write it to the cell.
What should happen is if there is a match, z= 5182 and x= 9999 (or arbitrary large number) and since 5182 < 9999 it doesn't do anything.
Is my scope wrong? Or am I not writing the If/Else correctly? Or is it something else?
Your code performs a strict comparison between the elements of two Arrays. That's fine, in general. However, for those specific Arrays those elements are also Arrays, which means strict (in)equality is checking to see if those are the exact same array object in memory. See this question for more information.
You probably wanted to do a value-based comparison, which means you need to compare the specific element of that inner array (i.e., index again). if (array2[i][0] !== array1[j][0]) {...} will check the 1st element of the inner array.
Looking at the instantiation of array1 and array2, we see that these are indeed 2D arrays from a single-column Ranges, so there will be only 1 element in each inner array. You can reduce the level of indexing necessary by flattening these arrays when you read them:
const array1 = sheet.getRange(...).getValues().map(function (row) { return row[0]; });
const array2 = ...;
I'm also not sure why you are passing in arrays to Sheet#getRange - you should pass in 1-4 arguments in manners consistent with the method signatures detailed in the Apps Script documentation.
Note that there are much better algorithms for checking if a value exists in a given array - you re-scan all of the 2nd array for every value of the first array. You should conduct thorough research into this topic before asking a new question on how to improve your algorithm.
Lastly, you should implement the best practice of using batch methods - you currently call setValue in a loop. Consider storing the results to write in an array, and then writing with Range#setValues once your loop has completed. There are many questions available for you to review on this topic.

Create a Stream using Scanner

This is usually how I accept an Array from a user. I ask for the size, then loop and populate the Array.
Scanner scan = new Scanner(System.in);
int N = scan.nextInt();
int[] numbers = new int[N];
for (int n=0; n<N; n++){
numbers[n] = scan.nextInt();
}
I have been trying to learn java 8 and I noticed that the Random class has a method now to create a stream. It is pretty easy now to declare a n-sized array with random numbers.
int[] randomNumbers = new Random().ints().limit(N).toArray();
What I have been trying to do is create an array doing something similar with either streams or lambda expressions but for user input. What I tried doing is creating an IntStream, map the values to Scanner#nextInt, then create an array.
int[] numbers = new IntStream().map(x -> scan.nextInt()).limit(N).toArray();
What I can do is something like this:
int[] numbers = new int[N];
Arrays.fill(numbers, 0);
numbers = Arrays.stream(numbers).map(x -> scan.nextInt()).toArray();
System.out.println(Arrays.toString(numbers));
But that still feels a bit redundant. Filling the array with some arbitrary number only to replace it in the next line.
Due to the way, the current implementation handles limit(…)s, it’s more efficient to create a stream using:
IntStream.range(0, N).map(i -> scan.nextInt())
which will be more efficient when using toArray() as well as for parallel processing despite creating an otherwise unused value with the range operation. Further, this creates an ordered stream which maintains the element order.
So when using,
int[] numbers = IntStream.range(0, N).map(i -> scan.nextInt()).toArray();
it benefits from knowing the array size in advance.
Use IntStream.generate:
int[] numbers = IntStream.generate(() -> scan.nextInt()).limit(N).toArray();
As mentionned in the comments, this generates an unordered stream. If you want it to be ordered, you can use:
IntStream.range(0, N).map(i -> scan.nextInt()).toArray();

How to get N unique random quantities without indefinite loop?

I want to generate 5 random positions on a map. I can only come up with the code below, which uses while (1) and break:
int map[10][10];
memset(map,0,sizeof(map));
for (int i = 0; i < 5; i++) {
while (1) {
int x = RAND_FROM_TO(0, 10);
int y = RAND_FROM_TO(0, 10);
if (map[x][y]==0) {
map[x][y]=1;
break;
}
}
}
Is there any other way to do the same job without while(1), because I have been told the while(1) is very bad.
I just want to find a simple way to do it, so the efficiency of the generating random numbers is not under my consideration.
You can use a shuffle algorithm such as Fisher–Yates. I would pose a modified (truncated) version as so:
Express your XY coordinates as a single number.
Construct a list of all coordinates.
Pick one at random, mark it.
Remove that coordinate from the list (swap it with the one at the end of the list, and treat the list as 1 element shorter)
repeat with the list that no longer contains the marked coordinate.
This way, rather than choosing 5 numbers from 0-99, you choose one 0-99, 0-98, ... 0-95, which guarantees that you can complete the task with exactly 5 choices.
EDIT: Upon further consideration, step 1 is not strictly necessary, and you could use this on a system with sparse coordinates if you did it that way.
What about something like this:
// Create an array of valid indexes for both x and y.
NSMutableArray *xCoords = [NSMutableArray array];
NSMutableArray *yCoords = [NSMutableArray array];
for (int i = 0; i < 9; ++i) {
[xCoords addObject:#(i)];
[yCoords addObject:#(i)];
}
int map[10][10];
memset(map, 0, sizeof(map));
for (int i = 0; i < 5; ++i) {
// Pick a random x coordinate from the valid x coordinate list.
int rand = RAND_FROM_TO(0, [xCoords count]);
int x = [xCoords objectAtIndex:rand];
// Now remove that coordinate so it cannot be picked again.
[xCoords removeObjectAtIndex:rand];
// Repeat for y.
rand = RAND_FROM_TO(0, [yCoords count]);
int y = [yCoords objectAtIndex:rand];
[yCoords removeObjectAtIndex:rand];
assert(map[x][y] == 0);
map[x][y] = 1;
}
Note: I'm using NSMutableArray because you originally specified Objective-C as a tag.
Note 2: An array of valid indexes is not the most efficient representation. Using NSMutableIndexSet instead is left as an exercise to the reader. As is using basic C primitives if you don't / can't use NSMutableArray.
Note 3: This has a bug where if you pick, say, x = 3 the first time, no further choices will end up with x = 3, even though there will be valid choices where x = 3 but y is different. Fixing that is also left as an exercise, but this does satisfy your requirements, on the surface.

How to do a simple random sort of values within an array

I need to sort these values randomly in an array.
int [] d = new int[26];
d[0]=1;
d[1]=5;
d[2]=10;
d[3]=25;
d[4]=50;
d[5]=75;
d[6]=100;
d[7]=200;
d[8]=300;
d[9]=400;
d[10]=500;
d[11]=750;
d[12]=1000;
d[13]=2000;
d[14]=3000;
d[15]=4000;
d[16]=5000;
d[17]=7500;
d[18]=10000;
d[19]=25000;
d[20]=50000;
d[21]=100000;
d[22]=250000;
d[23]=500000;
d[24]=750000;
d[25]=1000000;
Assuming you are writing this in C++ you can use random_shuffle function template from the Standard library. http://www.cppreference.com/wiki/algorithm/random_shuffle
If you want to write your own function, simply take two random indices and swap their values. Put that in a loop and do it as many times as think necessary for the array to be well shuffled (I would say a number of times equal to two times the number of elements in the array).
In psudo-code (since you haven't indicated the language)
NUMBER_OF_SHUFFLES = 2;
for(ix = 0; ix < NUMBER_OF_SHUFFLES * myArray.length; ix++)
index1 = random(myArray.length)
index2 = random(myArray.length)
temp = index1
myArray[index1] = myArray[index2]
myArray[index2] = temp
There are more sophisticated ways of doing it as well. Check out this discussion: An Efficient way of randomizing an array - Shuffle code
If it's java you may use
Arrays.shuffle(d);

Resources