Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: batching integers

I was wondering what the best way is to batch a given set of numbers in terms of a processing time. Take items: 9, 18, 7, 8, 4, 9, 11, 15, 3, 8, (item 1 has a processing time of 9, item 2 has a processing time of 18, etc.)

If the batch processing time limit is set to say 20, then a possible grouping of the items into batches would be:{1, 3, 5} {2} {4, 6} {8, 9} {7, 10} (group 1 is 9+7+4=20) etc so 5 batches of items have been made where the contents are <= 20.

Ideally i want it to sort them into as fewer groups as possible. Above's case is a minimum of 5 groups with a content limit of 20...

Thanks

like image 845
binary101 Avatar asked Nov 28 '12 19:11

binary101


2 Answers

If the batch processing time limit is set to say 20,...

So I assume that there is no element greater than batch processing time limit. Here is my approach:

  • Firstly sort the items. Then get 2 pointers for the list, one is at index 0 (left-pointer) and the other one at the last index (right-pointer).
  • Take the element of right-pointer and add it to a sublist. Take the element of left-pointer and add it to the same sublist. If the sum of the elements in sublist is less than limit, update left-pointer (set it to next element) and try adding it. Continue this process until a sublist is filled.
  • Then start filling the next sublist. Consume all elements to construct sublists.

Implementation in Java:

int[] input = { 9, 18, 7, 8, 4, 9, 11, 15, 3, 8 }; // Input items.
Arrays.sort(input); // Sort the items.
int left = 0, right = input.length - 1; // Left and right pointers.
int remainder = 0, limit = 20;

// list of groups.
ArrayList<ArrayList<Integer>> list = new ArrayList<ArrayList<Integer>>();

while (right >= left) 
{
    ArrayList<Integer> subList = new ArrayList<Integer>();
    list.add(subList);
    // Add the current maximum element.
    subList.add(input[right]);
    if (right == left)
        break;
    remainder = limit - input[right];
    right--;

    // Add small elements until limit is reached.
    while (remainder > input[left]) {
        subList.add(input[left]);
        remainder = remainder - input[left];
        left++;
    }

    remainder = 0; // Reset the remainder.
}

Printing the groups:

for (ArrayList<Integer> subList : list) 
{
    for (int i : subList)
        System.out.print(i + " ");
    System.out.println();
}

Output: (Each line denotes a group of numbers)

18 
15 3 
11 4 
9 7 
9 8
8
like image 181
Juvanis Avatar answered Sep 27 '22 17:09

Juvanis


  1. Take the biggest from the IN set and put in a new set S. (item 2, value 18)
  2. Try to find the biggest item with value <= (20 - 18): none, add S to a list of set.
  3. if IN is not empty GOTO 1

Iterations :

                            IN: 9, 18, 7, 8, 4, 9, 11, 15, 3, 8
 S1 (18) :  2:18            IN: 9,  _, 7, 8, 4, 9, 11, 15, 3, 8
 S2 (19) :  8:15, 5:4       IN: 9,  _, 7, 8, _, 9, 11,  _, 3, 8
 S3 (20) :  7:11, 1:9       IN: _,  _, 7, 8, _, 9,  _,  _, 3, 8
 S4 (20) :  6: 9, 4:8, 0:3  IN: _,  _, 7, _, _, _,  _,  _, _, 8
 S5 (15) : 10: 8, 3:7       IN: _,  _, _, _, _, _,  _,  _, _, _

The code :

public class Knapsack {
   public static void knapsack( int capacity, int[] values, List< int[] > indices ) {
      int[]           in         = Arrays.copyOf( values, values.length );
      List< Integer > workspace  = new LinkedList<>();
      int             wCapacity  = capacity;
      boolean         inProgress = true;
      while( inProgress ) {
         int greatestValue = -1;
         int greatestIndex = -1;
         for( int i = 0; i < in.length; ++i ) {
            int value = in[i];
            if(   value > Integer.MIN_VALUE
               && greatestValue < value && value <= wCapacity )
            {
               greatestValue = value;
               greatestIndex = i;
            }
         }
         if( greatestIndex >= 0 ) {
            workspace.add( greatestIndex );
            in[greatestIndex] = Integer.MIN_VALUE;
            wCapacity -= greatestValue;
         } else if( workspace.isEmpty()) {
            inProgress = false;
         } else {
            int[] ws = new int[workspace.size()];
            for( int i = 0; i < workspace.size(); ++i ) {
               ws[i] = workspace.get(i).intValue();
            }
            indices.add( ws );
            workspace = new LinkedList<>();
            wCapacity = capacity;
         }
      }
   }
   static void print( int[] values, List< int[] > indices )
   {
      int r = 0;
      for( int[] t : indices ) {
         String items = "";
         int    sum   = 0;
         for( int index : t ) {
            int value = values[index];
            if( ! items.isEmpty()) {
               items += ", ";
            }
            items += index + ":" + value;
            sum += value;
         }
         System.out.println( "S" + ++r + " (" + sum + ") : " + items );
      }
   }
   public static void main( String[] args ) {
      int[]         values  = { 9, 18, 7, 8, 4, 9, 11, 15, 3, 8 };
      List< int[] > indices = new LinkedList<>();
      knapsack( 20, values, indices );
      print( values, indices );
   }
}

The result:

S1 (18) : 1:18
S2 (19) : 7:15, 4:4
S3 (20) : 6:11, 0:9
S4 (20) : 5:9, 3:8, 8:3
S5 (15) : 9:8, 2:7
like image 30
Aubin Avatar answered Sep 27 '22 17:09

Aubin