Getting n random elements in array - java

I want to get n unique random elements from my array.
For example:
if n = 4;
I want to randomly get
array[0], array[3], array[7], array[2]
The problem is getting a random integer will lead to collisions easily (psuedocode):
for n times
{
r = generateRandomInteger within n-1
list.push(array[r]); //array[r] can be the same.
}
collisions abound, especially on small arrays.
What's a particularly elegant way to solve this?

You can use a Set instead of a List which will eliminate the duplicates. Accordingly you'll need to change your loop condition as well. Something like this
while set.size() is less than n
{
r = generateRandomInteger within n-1
set.add(array[r]); //if its the same, it won't be added to the set and the size won't increase
}

You can do this two way : i suggest you to use first one .
First by using SET :
for n times
{
r = generateRandomInteger within n-1
// you can use SET instead of LIST cause SET not allow duplication.
set.push(array[r]); //array[r] can be the same.
}
Second by using LIST :
for n times
{
r = generateRandomInteger within n-1
if(!list.contains(array[r]))
list.push(array[r]); //array[r] can be the same.
}

You can add all random ints to a list and generate a new random, till the list doesnt contains this random int. Thats not the best performance, but it works.
List<Integer> randoms = new ArrayList<Integer>()
for(int i=0; i<n;i++){
while(randoms.contains(r)) {
r = Random.nextInt(array.length-1);
}
randoms.add(r);
list.push(array[r]);
}

Using a Set is probably the best thing to do.
If you want unique elements from array (i.e. the values of array[]) then use R.J's solution. If you want unique indices:
while set.size() is less than n
{
r = generateRandomInteger within n-1
set.add(r);
}
foreach(r: set)
{
list.add(array[r]);
}
Be carefull if you want more elements then the length of the array, since you will get an infinite loop:
if(n>array.length)
{
print("Cannot get more then ... elements!");
return null;
}

int n = 4;
for (int i = 0; i < n; i++)
{
int index = RandomBetweenInclusive(i, array.length() - 1); //made up function
int temp = array[i];
array[i] = array[index];
array[index] = array[i];
}
//array values between indices 0 and n-1 will be random and unique values of array

What I usually do in this scenario is push all the items I want to select-from into a collection
var selectFrom = original.clone; // or build array
var selected = new collection;
Then I go about removing random elements in the selectFrom collection
for (i = 0; i < toSelect; i++)
{
var rndItem = selectFrom[ rand() * selectFrom.length ];
selected.add(rndItem);
selectFrom.remove(rndItem);
}
This way I select randomly from what remains and do not have to worry about clashes in random numbers / indexs.

Related

Java Remove method to return new array removing occurences of integer (no arraylist)

I am trying to create a method (without using arraylist) to return a new array that removes all instances of some integer (call it x). (For example, b=[2,5,3,2,7] b.remove(2) would return [5,3,7]. This code I have been working on (one of several hours worth of different attempts) seems to work when there is one occurence of X, but not many. When there are many, it sizes the new array correctly, but does not copy the data correctly for at/after the second occurence of X.
What I am trying to do is set a counter for each time X occurs, then set a new array that has length (old array length - count variable). Then I need to shift all the data after any occurence of X left. Here's my current code:
public Sequence remove(int n) {
int count = 0;
int a = 0;
for (int z=0; z < this.values.length; z++) {
if (this.values[z] == n)
count++;
}
Sequence newSequence = new Sequence(this.values.length - count);
for (int b=0; b < this.values.length - count; b++) {
if (this.values[a] != n) {
newSequence.values[a] = this.values[a];
a++;
} else {
newSequence.values[a]=this.values[a+1];
}
}
return newSequence;
}
I think the logic for populating the new resized array should be something like this:
walk through the entire original array
if a given value be the one you want removed, do nothing
otherwise add it to the new array and also increment the index in the new array
int pos = 0; // keeps track of position in newSequence.values
for (int i=0; i < this.values.length; i++) {
if (this.values[i] != n) {
newSequence.values[pos] = this.values[i];
pos++;
}
}
To be honest I did not completely get what you trying to do. But I understood the problem and your code. I would follow these steps to solve this problem.
Iterate through the array and count the number of times n (assuming you want to remove n) occurs. This count is stored in count variable.
Create a new array with size values.length-count (here values is the array)
Copy numbers from values array to new array.
This gives a O(n) solution.

How to know the fewest numbers we should add to get a full array

recently I met a question like this:
Assume you have an int N, and you also have an int[] and each element in this array can only be used once time. And we need to design an algorithm to get 1 to N by adding those numbers and finally return the least numbers we need to add.
For example:
N = 6, array is [1,3]
1 : we already have.
2 : we need to add it to the array.
3 : we can get it by doing 1 + 2.
4: 1 + 3.
5 : 2 + 3.
6 : 1 + 2 + 3.
So we just need to add 2 to our array and finally we return 1.
I am thinking of solving this by using DFS.
Do you have some better solutions? Thanks!
Here's an explanation for why the solution the OP posted works (the algorithm, briefly, is to traverse the sorted existing elements, keep an accumulating sum of the preceding existing elements and add an element to the array and sum if it does not exist and exceeds the current sum):
The loop tests in order each element that must be formed and sums the preceding elements. It alerts us if there is an element needed that's greater than the current sum. If you think about it, it's really simple! How could we make the element when we've already used all the preceding elements, which is what the sum represents!
In contrast, how do we know that all the intermediate elements will be able to be formed when the sum is larger than the current element? For example, consider n = 7, a = {}:
The function adds {1,2,4...}
So we are up to 4 and we know 1,2,3,4 are covered,
each can be formed from equal or lower numbers in the array.
At any point, m, in the traversal, we know for sure that
X0 + X1 ... + Xm make the largest number we can make, call it Y.
But we also know that we can make 1,2,3...Xm
Therefore, we can make Y-1, Y-2, Y-3...Y-Xm
(In this example: Xm = 4; Y = 1+2+4 = 7; Y-1 = 6; Y-2 = 5)
Q.E.D.
I don't know if this is a good solution or not:
I would create a second array (boolean array) remembering all numbers I can calculate.
Then I would write a method simulating the adding of a number to the array. (In your example the 1, 3 and 2 are added to the array).
The boolean array will be updated to always remember which values (numbers) can be calculated with the added numbers.
After calling the add method on the initial array values, you test for every Number x ( 1 <= x <= N ) if x can be calculated. If not call the add method for x.
since my explanation is no good I will add (untested) Java code:
static int[] arr = {3,5};
static int N = 20;
//An Array remembering which values can be calculated so far
static boolean[] canCalculate = new boolean[N];
//Calculate how many numbers must be added to the array ( Runtime O(N^2) )
public static int method(){
//Preperation (adding every given Number in the array)
for(int i=0; i<arr.length; i++){
addNumber(arr[i]);
}
//The number of elements added to the initial array
int result = 0;
//Adding (and counting) the missing numbers (Runtime O(N^2) )
for(int i=1; i<=N; i++){
if( !canCalculate[i-1] ){
addNumber(i);
result++;
}
}
return result;
}
//This Method is called whenever a new number is added to your array
//runtime O(N)
public static void addNumber( int number ){
System.out.println("Add Number: "+(number));
boolean[] newarray = new boolean[N];
newarray[number-1] = true;
//Test which values can be calculated after adding this number
//And update the array
for(int i=1; i<=N; i++){
if( canCalculate[i-1] ){
newarray[i-1] = true;
if( i + number <= N ){
newarray[i+number-1] = true;
}
}
}
canCalculate = newarray;
}
Edit: Tested the code and changed some errors (but rachel's solution seems to be better anyway)
It is a famous problem from dynamic programming. You can refer to complete solution here https://www.youtube.com/watch?v=s6FhG--P7z0
I just found a possible solution like this
public static int getNum(int n, int[] a) {
ArrayList<Integer> output = new ArrayList<Integer>();
Arrays.sort(a);
int sum = 0;
int i = 0;
while(true) {
if (i >= a.length || a[i] > sum + 1) {
output.add(sum + 1);
sum += sum + 1;
} else {
sum += a[i];
i++;
}
if (sum >= n) {
break;
}
}
return output.size();
};
And I test some cases and it looks correct.
But the one who write this didn't give us any hints and I am really confused with this one. Can anybody come up with some explanations ? Thanks!

(Java) Method to find number divisible by a number and add to array to be print out

I want to make a method to find a number divisible by a number and add those numbers to an array to be printed out later when I call the method.
I made it to this point:
int [] divider(int n) {
int [] result = new int[20];
for (int i = 0; i <= n; i++) {
if (n%i == 0)
result = result[i];
}
return result;
}
I know it's wrong at many points, but I tried. This is the two thing I know I need to do, but I don't know how:
I know that I have the calculate how many numbers that divisible by a number first to know how big of an array to create. The problem is I know how to find how many number there are, but I don't know how to use that number to create an array by itself in the method.
After that I need to find what is those numbers in which it can divide by another number. This one I could do it, but I don't know how to add these result into an array to print out later.
These are what I know up until now. Please help. Thank you.
Here is the test:
public static void main(String[] args) {
Integer [] arr = divider(60);
for (Integer integer : arr) {
System.out.println(integer);
}
}
You should finish your loop with "n/2" because second max divider of "n" must be "n/2": i.e: second max divider of 60 is 30. and "i" must start with "1" because you can not divide a number with "0". After loop finihed we should add "n" into the list because max divider of "n" is "n".
static Integer [] divider(int n) {
List<Integer> resultList = new ArrayList<Integer>();
Integer [] result;
for (int i = 1; i <= n/2; i++) {
if (n%i == 0)
resultList.add(i);
}
resultList.add(n);
result = resultList.toArray(new Integer[resultList.size()]);
return result;
}
This can be done without a List since you can bound the number of numbers that divide your input n. The most trivial way to do it is to say that n cannot have more than n dividers. A more clever bound is sqrt(n). You wanted a size for your array ? Here it is : sqrt(n) + 1 (+1 for a perfect square).
At the end of the method, you can count the actual number of dividers and copy them into a new array. This method may be less efficient than using a List, but if you are limited to arrays this is the way to go.
you can try to add them to a ArrayList instead, for ArrayList you don't need to know the size before hand, you can just add them as you go along, also for your look you don't have to look at all 1 to n-1 numbers.
if you can't change the definition of your method, then as below you can just add them to a new array. if you can change the definition then you can simply return the result.
int[] divider(int n) {
ArrayList<Integer> result=new ArrayList<Integer>();
for (int i = 1; i <= n/2; i++) { //only check for half of the numbers
if (n%i == 0)
result = result[i];
}
int[] a=new int[result.size()];
for(int i=0;i<a.length;i++){
a[i]=results.get(i);
}
return a;
}

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.

Sqrt, and Math in Arrays

I'm having difficulty understand how to write this array. I need it to out-print 10x5 (50 elements total), and have the first 25 elements equal to the sqrt of the index that it is in, and the last 25 to equal 3 * the index. Yes, this is homework but I'm not asking for you to do it for me, I just need help! I'm getting errors when using Math saying that I cant use double and the double array together. Here is what I have so far:
public class snhu4 {
public static void main(String args[]) {
double alpha[][] = new double[10][5];
double[] sum, sum2;
for (int count=0; count<=25;count++) {
alpha[count]= Math.sqrt(count);
}
for (int count=26; count<=50;count++) {
alpha[count]= count *3;
}
for (int count=0; count<=50;count++) {
System.out.print(alpha[count]);
}
}
}
Because alpha is a multidimensional array, you can't refer to its elements like a normal array.
int myarray[][] = new int[2][2];
In the above example, the array myarray is multidimensional. If I wanted to access the second element in the first array, I would access it like this:
int myint = myarray[0][1];
You are trying to access a multidimensional array by using the access for a normal array. Change
alpha[count]
to
alpha[0][count]
or similar.
Read here for more information on multidimensional arrays.
you defined alpha as a 2D array with lets say 10 items in the first dimension and 5 in the second, and 5x10 is 50 elements.
When using your array to assign values to these elements, u must call upon the array using 2 indices, one for each dimension:
alpha[i][j] = /*double value*/; //with 0<=i<=9 and 0<=j<=4
So the first 25 elements going from left to right in dimension order is going to be:
[0to9][0] and [0to9][1] and [0to4][2]
the next 25 will be
[4to9][2] and [0to9][3] and [0to9][4]
from then on i cannot give you the answers to your homework, but the loops should look like this:
int j;
for(int i = 0; i<25; i++)
{
j=i/10; //integer division will return 0 for i<10, 1 for 10<i<20, etc..
alpha[i%10][j] = Math.sqrt(i);
}
and you can figure out the rest
The 10x5 appears to be an output constraint, not a design constraint.
You are using Java, so use Java constructs, not C-language constructs;
specifically store the values in a List not an array.
Here are some hints:
List<Integer> valuesList = new ArrayList<Integer>();
for (int index = 0; index < 25; ++index)
Integer currentValue = Math.sqrt(index);
valuesList.add(currentValue);
for (int index = 25; index < 50; ++index)
Integer currentValue = index * 3;
valuesList.add(currentValue)
int count = 1;
for (Integer current : valuesList)
if ((count % 5) == 0) // write a newline.
System.out.print(current);
++count

Categories