5

Suppose I have the array:

array(1,1,2,1,4,5,7,2,3);

What would be the fastest way to get these numbers into x arrays we'll use 3 and have the numbers be as equal as possible with the larger numbers at the end?

Example:

array(1, 1, 1, 5);
array(7, 2);
array(4, 2, 3);

I'm worried that this might be a p=np problem but it seems so simple that it shouldn't be. I just can't seem to figure it out.

Similar question: Algorithm to split an array into P subarrays of balanced sum

Community
  • 1
  • 1
Blakethepatton
  • 537
  • 6
  • 17
  • what is basis of your out put.? how's you write it? – Alive to die - Anant Nov 18 '15 at 19:59
  • 2
    What do you mean by _with the larger numbers at the end_? – AbraCadaver Nov 18 '15 at 20:00
  • Total of the numbers in the first array is 26 so then there should be two totals of 9 and one of 8, that's the basis of my output. I don't know how to achieve this efficiently – Blakethepatton Nov 18 '15 at 20:01
  • 1
    Well, do it inefficiently and we'll try to make it efficient. – AbraCadaver Nov 18 '15 at 20:02
  • http://pastebin.com/X32Ly3TH Something like that however if there was a large number in the 4th column the script fails. It's sudocode but it should get the idea across. – Blakethepatton Nov 18 '15 at 20:11
  • Not sure if I've understood you correctly. You want to take an array of integers, and then split it into an arbitrary number of arrays that contain all of the original numbers such that the sum of each array is as close to each other's sums as possible, sorted from smallest sum to largest? Sort of like taking a pile of coins (of different denominations) and trying to make an certain number of even piles (as close as you can)? – jaredk Nov 18 '15 at 20:24
  • @jaredk That's correct. Sorry for being so vague. – Blakethepatton Nov 18 '15 at 20:27
  • @Blakethepatton It's no problem. Consider editing your question to make the whole "even sums" requirement more obvious. It's an interesting puzzle that I don't have a quick answer to. – jaredk Nov 18 '15 at 20:29
  • 2
    don't delete and repost the same question. It's very rude. –  Nov 18 '15 at 20:35

2 Answers2

2

Essentially you can use array_slice to strip out the chunks you need and asort to sort the array from least to greatest first.

The code below will do the trick:

(edit: after a recent comment I'm confused, are you saying you want the sum of the numbers in the array to be close to the same? I thought you meant you wanted the arrays to be evenly split in size not sum?)

$arr = array(1,1,2,1,4,5,7,2,3);
asort($arr); // sort the array

$x = 3; // number of arrays
$offset = ceil(count($arr) / $x);

$newArrays = array();
for($i=0;$i<=count($arr)-1;$i+=$offset) {
  $newArrays[] = array_slice($arr,$i,$offset);
}

var_dump($newArrays);

Result:

array(3) {
  [0]=>
  array(3) {
    [0]=>
    int(1)
    [1]=>
    int(1)
    [2]=>
    int(1)
  }
  [1]=>
  array(3) {
    [0]=>
    int(2)
    [1]=>
    int(2)
    [2]=>
    int(3)
  }
  [2]=>
  array(3) {
    [0]=>
    int(4)
    [1]=>
    int(5)
    [2]=>
    int(7)
  }
}
skrilled
  • 5,350
  • 2
  • 26
  • 48
  • 2
    Same user asked same question few hours ago, and just when I wanted to post answer, question was deleted... anyway, I was using same logic as you except we can use `array_chunk($array, $offset);` instead of for loop. :) – Nikola Miljković Nov 18 '15 at 20:27
  • I'm actually trying to get it so that arrays 1-3 have similar totals. Sorry for the confusion with the "Larger numbers at the end". What I meant by that is that for the total of 26 you'd have two arrays that total 9 and one with a total of 8. The way I'd like the output is with array one having the total of 8 and arrays 2&3 have a total of 9 – Blakethepatton Nov 18 '15 at 20:47
  • Evenly split by sums. I'm trying to split an array into P subarrays of balanced sum. IE Each of the subarays have about the same total. – Blakethepatton Nov 18 '15 at 22:18
2

Not exactly what you're looking for, but this should help get you started:

$array = array(1,1,2,1,4,5,7,2,3);

asort($array);

$total = array_sum($array);

$array1 = array();
$array2 = array();
$array3 = array();

foreach($array as $number) {
    if(array_sum($array1) < round($total / 3)) {
        array_push($array1, $number);
    } elseif(array_sum($array2) < round($total / 3)) {
        array_push($array2, $number);
    } else {
        array_push($array3, $number);
    }
}

for($i = 1; $i <= 3; $i++) {

    switch($i) {
        case 1:
            $op1 = 2;
            $op2 = 1;
            break;
        case 2:
            $op1 = -1;
            $op2 = 1;
            break;
        case 3:
            $op1 = -2;
            $op2 = -1;
            break;
    }

    foreach(${'array' . $i} as $number) {
        if((array_sum(${'array' . ($i + $op1)}) + $number) == round($total / 3)) {
            unset(${'array' . $i}[array_search($number, ${'array' . $i})]);
            array_push(${'array' . ($i + $op1)}, $number);
        } elseif((array_sum(${'array' . ($i + $op2)}) + $number) == round($total / 3)) {
            unset(${'array' . $i}[array_search($number, ${'array' . $i})]);
            array_push(${'array' . ($i + $op2)}, $number);
        }
    }
}

print_r($array1);
print_r($array2);
print_r($array3);

New Output:

Array
(
    [0] => 1
    [1] => 1
    [2] => 1
    [4] => 2
    [5] => 3
)
Array
(
    [0] => 4
    [1] => 5
)
Array
(
    [0] => 7
    [1] => 2
)
mattslone
  • 297
  • 1
  • 2
  • 14