-1

I have an array:

Array
(
    [1] => 25
    [2] => 50
    [3] => 25
)

I would like to make it into:

Array
(
    [1] => 50
    [2] => 50
)

To do this I split the middle value between 1 and 3. This is the simplest example, where the split is 50,50. I would like to be able to take a 15 element array down to 6 elements.

Any ideas?

Additional Examples [10, 15, 20, 25] Reduced to two elements: 25(10 + 15),45(20 + 25) [10, 10, 10, 10, 11] Reduced to two elements: 25(10 + 10 + (10/2)),26((10/2) + 10 + 11)

tereško
  • 58,060
  • 25
  • 98
  • 150
Davin
  • 137
  • 1
  • 2
  • 11
  • And I'm assuming this is homework? – cletus Jul 10 '09 at 16:38
  • How exactly does the algorithm look like? – Gumbo Jul 10 '09 at 16:38
  • Those arrays start at 0. And please elaborate the inner workings of this question, it is not clear. – tomzx Jul 10 '09 at 16:40
  • 15 elements = 6.6% per element 6 elements = 16% per element So in theory each of the new array will have the combined values of 3 the old values. Keeping it simple, if each of the 15 elements had a value of 1. Then the new array would have 6 elements with a value of about 3 each. – Davin Jul 10 '09 at 16:41
  • We need more information on the semantics of this algorithm; What would your expected array look like for [10, 15, 20, 25] or [10, 10, 10, 10, 11]? – Ron Warholic Jul 10 '09 at 16:41
  • [10, 15, 20, 25] Reduced to two elemnts: 25(10 + 15),45(20 + 25) – Davin Jul 10 '09 at 16:43
  • [10, 10, 10, 10, 11] Reduced to two elements: 25(10 + 10 + (10/2)),26((10/2) + 10 + 11) – Davin Jul 10 '09 at 16:44
  • I think we still need more information about your algorithm. Maybe you can name some rules how an arbitrary amount of values are calculated. – Gumbo Jul 10 '09 at 16:57
  • I was thinking: of a nested three loop system (4 for original and 2 for requested) 1.) Number of elements in requested size(2) 2.) % of current original value needed to satisfy chunk (50% = 100/2) 3.) % of current value (25% = 100/4) This would mean I would run 1.)2 times, 2.)2 times (50+50 = 100) 3.)1 times as I would completely use all the value of the original. – Davin Jul 10 '09 at 17:07
  • If each one of the original array is [10, 15, 20, 25] and the requested size is two: 10 + 15 = 25 and 20 + 25 = 45 so the resulting array is [25, 45] – Davin Jul 10 '09 at 17:09
  • [10, 10, 10, 10, 11] and the requested size is two: The original split is 20% of each and the requested size is 50% each. So 10 + 10 + 5(10 /2) (20% + 20% + 10% (20% / 2) = 50%) = 45 and 5(10 /2) + 10 + 11 (10% (20% / 2) + 20% + 20% = 50%) = 46 so the resulting array is [45,46] – Davin Jul 10 '09 at 17:12
  • The question does a poor job of explaining the required logic. Unclear. – mickmackusa Mar 30 '21 at 04:05

3 Answers3

2

After doing additional tests on Peter's solution, I noticed it did not get me what I expected if the reduce to size is an odd number. Here is the function I came up with. It also inflates data sets that are smaller then the requested size.

   <?php
        function reduceto($data,$r) {
            $c = count($data);

            // just enough data
            if ($c == $r) return $data;

            // not enough data
            if ($r > $c) {
                $x = ceil($r/$c);
                $temp = array();
                foreach ($data as $v) for($i = 0; $i < $x; $i++) $temp[] = $v;
                $data = $temp;
                $c = count($data);
            }

            // more data then needed
            if ($c > $r) {
                $temp = array();
                foreach ($data as $v) for($i = 0; $i < $r; $i++) $temp[] = $v;
                $data = array_map('array_sum',array_chunk($temp,$c));
            }
            foreach ($data as $k => $v) $data[$k] = $v / $r;
            return $data;
        }
    ?>
Davin
  • 137
  • 1
  • 2
  • 11
0

You could sum the values using array_sum() and then, depending on the number of elements you want to have in your resulting array, divide that sum and fill every element you want to keep with the result of your division.

(Here I'm assuming you'll use a second array, but you could unset the unneeded if you prefer it that way).

Nicolas
  • 2,158
  • 1
  • 17
  • 25
  • I would like to keep the distributed value percents the same. If I used the data to produce a bar graph, I need the reduce the data, but keep the overall shape of the graph. – Davin Jul 10 '09 at 16:55
0

Here's my stab at your issue

<pre>
<?php

class Thingy
{
  protected $store;
  protected $universe;

  public function __construct( array $data )
  {
    $this->store = $data;
    $this->universe = array_sum( $data );
  }

  public function reduceTo( $size )
  {
    //  Guard condition incase reduction size is too big
    $storeSize = count( $this->store );
    if ( $size >= $storeSize )
    {
      return $this->store;
    }

    //  Odd number of elements must be handled differently
    if ( $storeSize & 1 )
    {
      $chunked = array_chunk( $this->store, ceil( $storeSize / 2 ) );
      $middleValue = array_pop( $chunked[0] );

      $chunked = array_chunk( array_merge( $chunked[0], $chunked[1] ), floor( $storeSize / $size ) );

      //  Distribute odd-man-out amonst other values
      foreach ( $chunked as &$chunk )
      {
        $chunk[] = $middleValue / $size;
      }
    } else {
      $chunked = array_chunk( $this->store, floor( $storeSize / $size ) );
    }

    return array_map( 'array_sum', $chunked );
  }

}

$tests = array(
    array( 2, array( 25, 50, 25 ) )
  , array( 2, array( 10, 15, 20, 25 ) )
  , array( 2, array( 10, 10, 10, 10, 11 ) )
  , array( 6, array_fill( 0, 15, 1 ) )
);

foreach( $tests as $test )
{
  $t = new Thingy( $test[1] );
  print_r( $t->reduceTo( $test[0] ) );
}

?>
</pre>
Peter Bailey
  • 105,256
  • 31
  • 182
  • 206
  • The last example does not produce what I need, but I will work out this by doubling the data points until I reach more or equal to needed count. Thank you very much! – Davin Jul 10 '09 at 19:10