Dividing a number into smaller random ints

不羁岁月 提交于 2019-12-14 03:28:28

问题


So what i need is basically described in the subject.

Like if i would put in number 12 and amount of parts it should devide into, i would like it to return something like (with 4 parts) 8, 2, 1, 1. But not doubles because i need the values as int.
I had found one answer earlier but it only worked using doubles. not ints.
(this is the one i found)

public double[] divideUniformlyRandomly(double number, int part) {
    double uniformRandoms[] = new double[part];
    Random random = new Random();
    double mean = number / part;
    double sum = 0.0;
    for (int i=0; i<part / 2; i++) {
        uniformRandoms[i] = random.nextDouble() * mean;
        uniformRandoms[part - i - 1] = mean + random.nextDouble() * mean;
        sum += uniformRandoms[i] + uniformRandoms[part - i -1];
    }
    uniformRandoms[(int)Math.ceil(part/2)] = uniformRandoms[(int)Math.ceil(part/2)] + number - sum;
    return uniformRandoms;

I had tried changing this code to work using Ints by doing this:

public int[] divide(int number) {
    int part = getDivider(number);
    int uniformRandoms[] = new int[part];
    Random random = new Random();
    int mean = number / part;
    int sum = 0;
    for (int i=0; i<part / 2; i++) {
        uniformRandoms[i] = random.nextInt() * mean;
        uniformRandoms[part - i - 1] = mean + random.nextInt() * mean;
        sum += uniformRandoms[i] + uniformRandoms[part - i -1];
    }
    uniformRandoms[(int)Math.round(part/2)] = uniformRandoms[(int)Math.round(part/2)] + number - sum;
    for(int i : uniformRandoms)
        System.out.println(i);
    return uniformRandoms;
}

But when running that using number: 512 and using 10 parts (getDivider() will return 10) itll output this:

-1058809647, -2102647561, 469849949, 1627965716, -290084223, -33347991

And alot more of this kind of numbers.

Thanks.


回答1:


Assuming every term should at least be 1.

public int[] divide(int number, int parts) {
    int[] randoms = new int[parts];
    Arrays.fill(randoms, 1); // At least one
    int remainder = number - parts;
    Random random = new Random();
    for (int i = 0; i < parts - 1 && remainder > 0; ++i) {
        int diff = random.nextInt(remainder);
        randoms[i] += diff;
        remainder -= diff;
   }
   randoms[parts - 1] += remainder;
   Arrays.sort(randowms);

   // Reverse (for getting a descending array):
   for (int i = 0, j = parts - 1; i < j; ++i, --j) {h
       int temp = randoms[i];
       randoms[i] = randoms[j];
       randoms[j] = temp;
   }
   return randoms;
}

This is not uniformly distributed. For that one could iterate till remainder becomes 0, everytime randomly picking an index to increase. Or so. Have fun.

Was this homework?




回答2:


Use Random#nextInt(int)

public int[] divideUniformlyRandomly(int number, int parts) {
    Random random = new Random();
    int[] randoms = new int[];
    for(int i = 0; i < parts; i++) {
        randoms[randoms.length] = random.nextInt(number);
    }
    return randoms;
}



回答3:


Here's an algorithm which will do the job:

  1. Create an array of length parts+1.
  2. Add the values 0 and number to the array, then fill the remainder of it with unique random values using random.nextInt(number-1) + 1 to get values between 0 and number exclusive of the range limits.
  3. Sort the array.
  4. Iterate through the sorted array starting at index 1. The successive differences array[i] - array[i-1] will be a set of positive integers that sum to number.

If zeros are allowed, then you don't need the uniqueness criterion in filling the array. If you need uniqueness, you might consider adding random values to a HashSet (which only .add()'s unique entries) until the size meets your requirement, then convert it with .toArray().

Here's an actual implementation:

import java.util.Arrays;
import java.util.HashSet;
import java.util.Random;

public class SumToTotal {
   public static Random r = new Random();

   public static int[] divide(int number, int number_of_parts) {
      HashSet<Integer> uniqueInts = new HashSet<Integer>();
      uniqueInts.add(0);
      uniqueInts.add(number);
      int array_size = number_of_parts + 1;
      while (uniqueInts.size() < array_size) {
         uniqueInts.add(1 + r.nextInt(number - 1));
      }
      Integer[] dividers = uniqueInts.toArray(new Integer[array_size]);
      Arrays.sort(dividers);
      int[] results = new int[number_of_parts];
      for(int i = 1, j = 0; i < dividers.length; ++i, ++j) {
         results[j] = dividers[i] - dividers[j];
      }
      return results;
   }

   public static void main(String[] args) {
      System.out.println(Arrays.toString(divide(12, 5)));
   }
}

This produces results such as [3, 2, 1, 2, 4] or [1, 5, 2, 3, 1].




回答4:


A inefficient but very easy way would be to loop n times and increment one of the indices by one.

    void divider(int number, int divisions)
    {
        Random rand = new Random();
        int[] container = new int[divisions];

        System.out.print(number + "->");
        while (number > 0)
        {
            container[rand.nextInt(divisions)]++;
            number--;
        }
        for (int i : container)
        {
            System.out.print("[" + i + "]");
        }
    }

divider(1000, 20) could output:

1000->[57][43][60][35][39][47][45][59][51][71][52][54][58][48][33][49][49][46][49][55]
1000->[60][50][49][53][42][52][52][45][40][51][52][51][53][47][51][46][53][56][45][52]
1000->[52][43][49][53][57][45][42][43][61][61][58][44][46][49][52][39][63][45][54][44]

On my way to old PC it takes only 11ms to divide 100.000 in 20 different "containers". So if you are not using this very often and/or on very big numbers this is a perfectly valid way to do it.



来源:https://stackoverflow.com/questions/23613704/dividing-a-number-into-smaller-random-ints

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!