0

I'm looping through a multidimensional array and am left with some values.

This is the complete PHP code.


<?php 
/**
 * Each designer is required 3x per week, 
 * add their name 3 times to allow for the count.
 * 
 * [array_pop]  removes the designer from the sub-array
 * u[sort($designers, "sortByTotalItems")] then moves the designers with more names remaining to the top of the list
 *
 * @var [type]
 */
$designers = array(
    [ "Aaron Summers", "Aaron Summers", "Aaron Summers" ],
    [ "Adam Smart", "Adam Smart", "Adam Smart" ],
    [ "Andrew Montgomery", "Andrew Montgomery", "Andrew Montgomery" ],
    [ "Dave Robertson", "Dave Robertson", "Dave Robertson" ],
    [ "Holly Colby", "Holly Colby", "Holly Colby" ],
    [ "Karen Fok", "Karen Fok", "Karen Fok" ],
    [ "Kieran Lintott", "Kieran Lintott", "Kieran Lintott" ],
    [ "Rebecca Roffey", "Rebecca Roffey", "Rebecca Roffey" ],
    [ "Sonia Tam", "Sonia Tam", "Sonia Tam" ],
    [ "Steffi Wallace", "Steffi Wallace", "Steffi Wallace" ],
    [ "Taz Patel", "Taz Patel", "Taz Patel" ]
);
/**
 * Store the original designers to reset them once empty
 *
 * @var [type]
 */
$designers_bak = $designers;
/**
 * Generate an array of string dates between 2 dates
 *
 * @param string $start Start date
 * @param string $end End date
 * @param string $format Output format (Default: Y-m-d)
 *
 * @return array
 */
function getDatesFromRange( $start, $end ) {
    $array = array();
    $interval = new DateInterval('P1D');

    $realEnd = new DateTime($end);
    $realEnd->add($interval);

    $period = new DatePeriod(new DateTime($start), $interval, $realEnd);
    
    foreach($period as $date) { 
        $dayOfWeek = $date->format('l');
        if ( $dayOfWeek != 'Saturday' && $dayOfWeek != 'Sunday' ) {
            $array[] = $date->format('Y-m-d'); 
        }
    }

    return $array;
}
/**
 * Sort the array into sub-arrays that contain the most values
 * array(
 *     array('name', 'name', 'name')
 *     array('name', 'name')
 *     array('name')
 * )
 * https://stackoverflow.com/questions/7433569/php-sort-a-multidimensional-array-by-number-of-items#answer-7433753
 */
function sortByTotalItems($a, $b) {
    if ($a == $b) {
        return 0;
    }
    return (count($a) > count($b)) ? -1 : 1;
}
/**
 * Get the total amount of days in this week 1-5
 *
 * @var [type]
 */
$days_at_work = 3;
$total_days_in_week = 5;
$assigned_total = floor(count( $designers ) * $days_at_work / $total_days_in_week);    

/**
 * Each day
 *
 * @var [type]
 */
$working_weeks = array_chunk(getDatesFromRange('09-06-2021', '09-06-2022'), $total_days_in_week);
$given_designer = array();
foreach ( $working_weeks as $working_days ) {
    /**
     * Reset the designers
     *
     * @var [type]
     */
    foreach ( $working_days as $working_day ) {

        /**
         * Randomise the designers
         *
         * @var [type]
         */
        shuffle( $designers ); 
        /**
         * Sort the shuffle, so the sub-arrays count is descending
         * array(
         *     array('name', 'name', 'name')
         *     array('name', 'name')
         *     array('name')
         * )
         *
         * @var [$designers]
         */
        $designers = array_filter(array_map('array_filter', $designers));
        usort($designers, "sortByTotalItems");



        /**
         * Add designer to the working day
         *
         * @var [type]
         */

        $forcount = ( count($designers) < $assigned_total ) ? count($designers) : $assigned_total;



        for ($d=0; $d < $forcount; $d++) {
            /**
             * Add designer to the days visit
             *
             * @var [type]
             */

            $given_designer[] = array( 
                                    "title"=> $designers[$d][0],
                                    "start"=> $working_day
                                );
            /**
             * Remove the name from the names array -1 each loop
             *
             * @var [type]
             */
            array_pop($designers[$d]);
            /**
             * remove empty arrays so we can count the remaining designers
             * If there are less than 1 weeks worth of designers, reset the variable
             */
            $current_designers = array_filter(array_map('array_filter', $designers));
            if (  count($current_designers) < $assigned_total ) {
                $designers = $designers_bak;
            }
        }

        
    }  
}
?>

Below is what I'm left with after the loops and array_pop.

Let's call this array1

<?php 
array ( 0 => array ( ),
        1 => array ( ),
        2 => array ( ),
        3 => array ( ),
        4 => array ( 0 => 'Aaron Summers', ),
        5 => array ( 0 => 'Taz Patel', ),
        6 => array ( 0 => 'Sonia Tam', ),
        7 => array ( 0 => 'Adam Smart', ),
        8 => array ( 0 => 'Andrew Montgomery', ),
    ) 
?>

I then reset the array with the original values:

Let's call this array2

<?php
array ( 0 => array ( 0 => 'Aaron Summers', 1 => 'Aaron Summers', 2 => 'Aaron Summers', ),
        1 => array ( 0 => 'Adam Smart', 1 => 'Adam Smart', 2 => 'Adam Smart', ),
        2 => array ( 0 => 'Andrew Montgomery', 1 => 'Andrew Montgomery', 2 => 'Andrew Montgomery', ),
        3 => array ( 0 => 'Dave Robertson', 1 => 'Dave Robertson', 2 => 'Dave Robertson', ),
        4 => array ( 0 => 'Holly Colby', 1 => 'Holly Colby', ),
        5 => array ( 0 => 'Karen Fok', 1 => 'Karen Fok', 2 => 'Karen Fok', ),
        6 => array ( 0 => 'Kieran Lintott', 1 => 'Kieran Lintott', 2 => 'Kieran Lintott', ),
        7 => array ( 0 => 'Rebecca Roffey', 1 => 'Rebecca Roffey', 2 => 'Rebecca Roffey', ),
        8 => array ( 0 => 'Sonia Tam', 1 => 'Sonia Tam', 2 => 'Sonia Tam', ),
        9 => array ( 0 => 'Steffi Wallace', 1 => 'Steffi Wallace', 2 => 'Steffi Wallace', ),
        10 => array ( 0 => 'Taz Patel', 1 => 'Taz Patel', 2 => 'Taz Patel', ),
    )
?>

How would I be able to re-order the items in array2 based on the people left in array1 ?

array2 is the total size of the array and the array in its original form, before I have looped through and used array_pop() to remove the name.

Aaron
  • 10,187
  • 3
  • 23
  • 39
  • Well for a start you have magiced up some data in the second array, care to explain the logic there – RiggsFolly Jun 09 '21 at 18:23
  • Is this is total size of the array? Or could this be a very large array in realisty – RiggsFolly Jun 09 '21 at 18:24
  • **array2** is the total size of the array, I've updated my question with more details – Aaron Jun 09 '21 at 18:29
  • Well you are going to have to do this in couple of steps. First find all the names in the first array and place ina new array, sort it, then fake up 3 occurances of each name into the new array2 – RiggsFolly Jun 09 '21 at 18:31
  • I guess we should assume there were really 11 + empty occurances in array1 or how would we have managed to creat the missing 6 names – RiggsFolly Jun 09 '21 at 18:36
  • Ive updated my question with my complete code – Aaron Jun 09 '21 at 18:37
  • Always a GOOD Idea but only need [Minimal, Complete and Verifiable Example](http://stackoverflow.com/help/mcve) – RiggsFolly Jun 09 '21 at 18:41
  • I didn't want to confuse the question by adding so much code and just included where I was experiencing some difficulty. hence the arrays. – Aaron Jun 09 '21 at 19:01

2 Answers2

2

There are a couple of ways to do it, this being fairly simple since the names should be unique anyway:

$array2 = array_merge(array_column(array_filter($array1), null, 0), 
                      array_column($array2, null, 0));
  • Remove empties from the ordered array $array1, or do this to the final result after * see below
  • Index each array on the value, which should at least be at index 0
  • Merge the existing array into the ordered one, which will replace in the proper order and add the remaining names to the end

If you really need to get integer indexes then use array_values:

$array2 = array_values(array_filter(array_merge(array_column($array1, null, 0),
                                                array_column($array2, null, 0)));

Whatever you are doing with all of that code could probably be done much shorter and simpler if you use the name as the index in the first place.

AbraCadaver
  • 78,200
  • 7
  • 66
  • 87
  • Thank you AbraCadaver, I'm outputting the content to a json file, so wasn't able to output the names as keys. I'm still learning how to sort my arrays, it is for me, a tricky thing to understand. – Aaron Jun 09 '21 at 19:33
1

This will reorder $array2 (into a new variable $final). First it assembles a simple array $people of the names, then it reassembles $array2 by prioritizing based on the $people array. Was this what you wanted to accomplish?

<?php 
$array1 = array( 0 => array ( ),
        1 => array ( ),
        2 => array ( ),
        3 => array ( ),
        4 => array ( 0 => 'Aaron Summers', ),
        5 => array ( 0 => 'Taz Patel', ),
        6 => array ( 0 => 'Sonia Tam', ),
        7 => array ( 0 => 'Adam Smart', ),
        8 => array ( 0 => 'Andrew Montgomery', ),
    ) ;
    
    $people = [];
    foreach ($array1 as $a) { 
        if(count($a)>0 && $person = $a[0]) {
            $people[]= $person;
        }
    }

$array2 =array ( 0 => array ( 0 => 'Aaron Summers', 1 => 'Aaron Summers', 2 => 'Aaron Summers', ),
        1 => array ( 0 => 'Adam Smart', 1 => 'Adam Smart', 2 => 'Adam Smart', ),
        2 => array ( 0 => 'Andrew Montgomery', 1 => 'Andrew Montgomery', 2 => 'Andrew Montgomery', ),
        3 => array ( 0 => 'Dave Robertson', 1 => 'Dave Robertson', 2 => 'Dave Robertson', ),
        4 => array ( 0 => 'Holly Colby', 1 => 'Holly Colby', ),
        5 => array ( 0 => 'Karen Fok', 1 => 'Karen Fok', 2 => 'Karen Fok', ),
        6 => array ( 0 => 'Kieran Lintott', 1 => 'Kieran Lintott', 2 => 'Kieran Lintott', ),
        7 => array ( 0 => 'Rebecca Roffey', 1 => 'Rebecca Roffey', 2 => 'Rebecca Roffey', ),
        8 => array ( 0 => 'Sonia Tam', 1 => 'Sonia Tam', 2 => 'Sonia Tam', ),
        9 => array ( 0 => 'Steffi Wallace', 1 => 'Steffi Wallace', 2 => 'Steffi Wallace', ),
        10 => array ( 0 => 'Taz Patel', 1 => 'Taz Patel', 2 => 'Taz Patel', ),
    );
   $final=[];
    foreach($array2 as $a) {
       if (in_array($a[0], $people) !==false) array_unshift($final, $a);
       else $final[]=$a;
    }
    

print_r($final);
?>

Output:

Array
(
    [0] => Array
        (
            [0] => Taz Patel
            [1] => Taz Patel
            [2] => Taz Patel
        )

    [1] => Array
        (
            [0] => Sonia Tam
            [1] => Sonia Tam
            [2] => Sonia Tam
        )

    [2] => Array
        (
            [0] => Andrew Montgomery
            [1] => Andrew Montgomery
            [2] => Andrew Montgomery
        )

    [3] => Array
        (
            [0] => Adam Smart
            [1] => Adam Smart
            [2] => Adam Smart
        )

    [4] => Array
        (
            [0] => Aaron Summers
            [1] => Aaron Summers
            [2] => Aaron Summers
        )

    [5] => Array
        (
            [0] => Dave Robertson
            [1] => Dave Robertson
            [2] => Dave Robertson
        )

    [6] => Array
        (
            [0] => Holly Colby
            [1] => Holly Colby
        )

    [7] => Array
        (
            [0] => Karen Fok
            [1] => Karen Fok
            [2] => Karen Fok
        )

    [8] => Array
        (
            [0] => Kieran Lintott
            [1] => Kieran Lintott
            [2] => Kieran Lintott
        )

    [9] => Array
        (
            [0] => Rebecca Roffey
            [1] => Rebecca Roffey
            [2] => Rebecca Roffey
        )

    [10] => Array
        (
            [0] => Steffi Wallace
            [1] => Steffi Wallace
            [2] => Steffi Wallace
        )

)

https://www.tehplayground.com/zkrdHhL52a1ihqMY

Kinglish
  • 23,358
  • 3
  • 22
  • 43