Home > Software design >  Sort and group a 2d array by two columns to form a hierarchical 3d array then display data as HTML l
Sort and group a 2d array by two columns to form a hierarchical 3d array then display data as HTML l

Time:01-22

After sorting the $jobs array by location and territory_id values and then grouping them into arrays, I get an array which looks like the below - note I omitted most of the results inside each array since there's hundreds, but there should be a total of 18 arrays by territory_abbr key:

{
"PHL":[{"id":"28038a67e70c7e235fa725bbf8b6e167d9e3efee1e43a304d73be8408c6f24a2","posting_job_title":"Entry Level Sales Representative*","job_relationship":"w2_employee","location":"Aston, PA","territory_id":1,"territory_abbr":"PHL"},{"id":"7f8bcb16e0f3ffe9c8ce9aff2b6033bfbe582241e818aaf9c21506d509e70592","posting_job_title":"Sales Representative*","job_relationship":"w2_employee","location":"Aston, PA","territory_id":1,"territory_abbr":"PHL"},{"id":"7c6cc1c2abda3dae2edf0982f758073316491b27c240e5fa13df791e0fb5b744","posting_job_title":"Entry Level Sales Representative*","job_relationship":"w2_employee","location":"Aston, PA","territory_id":1,"territory_abbr":"PHL"}],
"NJ":[{"id":"31f1752e8c3f1086b4a1ed499e8786e1d15a8d1825cb75848056333d1cae8276","posting_job_title":"Entry Level Sales Representative*","job_relationship":"w2_employee","location":"Bridgewater, NJ","territory_id":2,"territory_abbr":"NJ"},{"id":"a74e36d026e3e062aac973e07968934f2a88472fa9fb1028dea439b557bd82a1","posting_job_title":"Sales Representative*","job_relationship":"w2_employee","location":"Bridgewater, NJ","territory_id":2,"territory_abbr":"NJ"},{"id":"889839e541fd5709077bd0c902d0183de8d091f694c1498e67853fd220c08ae9","posting_job_title":"Entry Level Sales Representative*","job_relationship":"w2_employee","location":"Bridgewater, NJ","territory_id":2,"territory_abbr":"NJ"}],
"MD":[{"id":"197c35000fb9b9ca1fe71771bb618c5443f0e7e51b59b9cad22f08d77d73de54","posting_job_title":"Siding Subcontractors Needed- Up To $10,000 SIGN ON BONUS","job_relationship":"company","location":"Aberdeen, MD","territory_id":3,"territory_abbr":"MD"},{"id":"8121cb7efb0e04130fbdc3f69468c7434c1582f71d71408ef689b81519d86a5c","posting_job_title":"Siding Subcontractors Needed- Up To $10,000 SIGN ON BONUS","job_relationship":"company","location":"Aberdeen, MD","territory_id":3,"territory_abbr":"MD"},{"id":"556b7ec84be0e6a5130cde5a441dc58ed595de5acd4e5f4883a2b2e6cc5eb4f4","posting_job_title":"Siding Subcontractors Needed- Up To $10,000 SIGN ON BONUS","job_relationship":"company","location":"Aberdeen, MD","territory_id":3,"territory_abbr":"MD"}],
"CT":[{"id":"b88924cfa34c25557381a63f9552074b4053f3e83dbe4c72564eb1cae3801a98","posting_job_title":"Sales Representative*","job_relationship":"w2_employee","location":"Bronx, NY","territory_id":4,"territory_abbr":"CT"},{"id":"8621ae18266b571175358113fd3ed7147f2ffa7d248c71c8e1a78b566ac24628","posting_job_title":"Sales Representative*","job_relationship":"w2_employee","location":"Bronx, NY","territory_id":4,"territory_abbr":"CT"},{"id":"bc2f7034687d2273f14bb2fa41fef8472f5e12ce8e483210b628167bba09c9aa","posting_job_title":"Sales Representative*","job_relationship":"w2_employee","location":"Bronx, NY","territory_id":4,"territory_abbr":"CT"}],
"LI":[{"id":"5debdc91afd45080a7cb87912b9411f186793e3ad9be8fbf8fe7f40f85ce9d17","posting_job_title":"Entry Level Sales Representative*","job_relationship":"w2_employee","location":"Bayside, NY","territory_id":5,"territory_abbr":"LI"},{"id":"3dc256cecd93030f3d4079b5a313277cc03f92fb2d991cf9b0b656a34f84425f","posting_job_title":"Entry Level Sales Representative*","job_relationship":"w2_employee","location":"Bayside, NY","territory_id":5,"territory_abbr":"LI"},{"id":"269e4edc7ed745210c71e8b324a5f2f559ba793f1ff67d5e61b00ee48b992d89","posting_job_title":"Sales Representative*","job_relationship":"w2_employee","location":"Bayside, NY","territory_id":5,"territory_abbr":"LI"}],
"BOS":[{"id":"498520c5b7fff98575b15dd442bc919b62bea6bcd5c3784a114e8c665a426013","posting_job_title":"Entry Level Sales Representative*","job_relationship":"w2_employee","location":"Ashland, MA","territory_id":6,"territory_abbr":"BOS"},{"id":"7e3bbd3af87cf3260b5c7a2aa557d867c7c1be0e87122a3c5af4d9b8fad7457d","posting_job_title":"Entry Level Sales Representative*","job_relationship":"w2_employee","location":"Ashland, MA","territory_id":6,"territory_abbr":"BOS"},{"id":"eccdf7304b1cb55fd77ed1a2b06ff07b8cf9885ab099a1e1b54b9eebc39fcaff","posting_job_title":"Entry Level Sales Representative*","job_relationship":"w2_employee","location":"Ashland, MA","territory_id":6,"territory_abbr":"BOS"}],
"ATL":[{"id":"52d6c40d7bc5b3d4045bc8c62bbc534b1029873769a26ad9eb077c53412f1ebd","posting_job_title":"Remodeling Consultant","job_relationship":"w2_employee","location":"Alpharetta, GA","territory_id":7,"territory_abbr":"ATL"},{"id":"ad50ef5eb9633b913111923c8084e1a3c1b3c306cb1cec38bd946b9a93e9251d","posting_job_title":"Sales Representative*","job_relationship":"w2_employee","location":"Alpharetta, GA","territory_id":7,"territory_abbr":"ATL"},{"id":"b256191b207364a1368d04f5d2e920383b8d140ec293e73f6a89b82033119e0d","posting_job_title":"Entry Level Sales Representative*","job_relationship":"w2_employee","location":"Alpharetta, GA","territory_id":7,"territory_abbr":"ATL"}],
"CHI":[{"id":"65341e3c52057461929c46ffbf590d846f504aedef36da6c6a4db36935200168","posting_job_title":"Roofing Installation Crews","job_relationship":"company","location":"Chicago, IL","territory_id":8,"territory_abbr":"CHI"},{"id":"4729ac73557d27ae83ca3a79cbe415bbfa64a6bd0b0db9a013db67a4a71fe9e5","posting_job_title":"Siding & Trim Installation Crews","job_relationship":"company","location":"Chicago, IL","territory_id":8,"territory_abbr":"CHI"},{"id":"f4473a812ad1b40d9b8e893afafa510f779c3077ecb38f73b9890809f0094ceb","posting_job_title":"Window & Door Installation Crews","job_relationship":"company","location":"Chicago, IL","territory_id":8,"territory_abbr":"CHI"}],
"DET":[{"id":"6c5f461dba3c81c77bbeb629769e82a84d63ebd30746fa8ebe90dc517873117c","posting_job_title":"Entry Level Sales Representative*","job_relationship":"w2_employee","location":"Ann Arbor, MI","territory_id":9,"territory_abbr":"DET"},{"id":"e7d8a95c99486a03b0686eb591d60eca3a552d00220cf49184ffa9f43a21f4aa","posting_job_title":"Sales Representative*","job_relationship":"w2_employee","location":"Ann Arbor, MI","territory_id":9,"territory_abbr":"DET"},{"id":"cb27d16da20e0c6f42b0285903a29fdc7edd51ed981e4133db8f7cf3948a3a19","posting_job_title":"Entry Level Sales Representative*","job_relationship":"w2_employee","location":"Ann Arbor, MI","territory_id":9,"territory_abbr":"DET"}],
"HOU":[{"id":"20ba14a427a0d740a98150fafa7d428dac321072bc0889efcee9f57032c68634","posting_job_title":"Entry Level Sales Representative*","job_relationship":"w2_employee","location":"Cypress, TX","territory_id":10,"territory_abbr":"HOU"},{"id":"2e41c93a2c2243cafa24bbab0e5291f5a411b88b9ffdc2273d821a91621d8262","posting_job_title":"Sales Representative*","job_relationship":"w2_employee","location":"Cypress, TX","territory_id":10,"territory_abbr":"HOU"},{"id":"3e2957a877ac2d7d3fcb02e52ba87303b78e8393beef17ffb1fe56f2a544d7a3","posting_job_title":"Sales Representative*","job_relationship":"w2_employee","location":"Cypress, TX","territory_id":10,"territory_abbr":"HOU"}],
"DAL":[{"id":"8a4f2e8d049566039672b2b411336a8b43de3035f6fc8fa92ff8c2b190ddc96b","posting_job_title":"Entry Level Sales Representative*","job_relationship":"w2_employee","location":"Arlington, TX","territory_id":11,"territory_abbr":"DAL"},{"id":"6de607ce972c23824d32179728282a0d2bc2c9bba4b3c6d9113b70975712e9d2","posting_job_title":"Sales Representative*","job_relationship":"w2_employee","location":"Arlington, TX","territory_id":11,"territory_abbr":"DAL"},{"id":"80b8fcb5cc6d581c4fc1e9be0bd48dd8db1b73474cdc920ed3a9665211cbbae4","posting_job_title":"Sales Representative*","job_relationship":"w2_employee","location":"Arlington, TX","territory_id":11,"territory_abbr":"DAL"}],
"DEN":[{"id":"a8f74d5ec1d31e3e43c4b6546631da15a5feb58f008adb4d6717e4627e25e68e","posting_job_title":"Sales Representative*","job_relationship":"w2_employee","location":"Aurora, CO","territory_id":12,"territory_abbr":"DEN"},{"id":"6b36d913d8e36d5e4c6a14558a50627bb5bcae278ac794c010864304be6b7400","posting_job_title":"Entry Level Sales Representative*","job_relationship":"w2_employee","location":"Aurora, CO","territory_id":12,"territory_abbr":"DEN"},{"id":"18f03346479a88c66f8b9e91ad4df042beff28270ddbd45cffd089be24a01fa0","posting_job_title":"Sales Representative*","job_relationship":"w2_employee","location":"Aurora, CO","territory_id":12,"territory_abbr":"DEN"}],
"TPA":[{"id":"06e9a1a02878dc977e59234a79fad805f732c4f92a9a3db717baa8ec1cb0f69c","posting_job_title":"Entry Level Sales Representative*","job_relationship":"w2_employee","location":"Lakeland, FL","territory_id":13,"territory_abbr":"TPA"},{"id":"0b10403a41d496052c30df684964e06165ea491b6a5ff29aa4ea818e1c9c7110","posting_job_title":"Sales Representative*","job_relationship":"w2_employee","location":"Lakeland, FL","territory_id":13,"territory_abbr":"TPA"},{"id":"d02541fc1d4df726375dce49140845b38c4c79e08c6b7c41e328adb160d8da51","posting_job_title":"Entry Level Sales Representative*","job_relationship":"w2_employee","location":"Lakeland, FL","territory_id":13,"territory_abbr":"TPA"}],
"AUS":[{"id":"452a16def02ae6d55fa9ea6cc2135a5a755954305c77b44587a7810622177ee4","posting_job_title":"Customer Development Representative","job_relationship":"w2_employee","location":"Austin, TX","territory_id":14,"territory_abbr":"AUS"},{"id":"3c8d9a8153faacbdde42799cd4a8f4f985522c1aa38a22d7838333c21376f78c","posting_job_title":"Window & Door Installation Crews","job_relationship":"company","location":"Austin, TX","territory_id":14,"territory_abbr":"AUS"},{"id":"65af00695e086cbebeb142f46a2f1e14f4f6665e77975b388cf4371bd083a485","posting_job_title":"Roofing Installation Crews","job_relationship":"company","location":"Austin, TX","territory_id":14,"territory_abbr":"AUS"}],
"CLT":[{"id":"00c184d45d6d237e6315f8fdf35f35498fd401fd6e5a24623600bf4ff3041c87","posting_job_title":"Customer Development Representative","job_relationship":"w2_employee","location":"Charlotte, NC","territory_id":15,"territory_abbr":"CLT"},{"id":"97a21226497c970195adda721302242629be3d6b4eb9245d5907b93fbd249f18","posting_job_title":"Window & Door Installation Crews","job_relationship":"company","location":"Charlotte, NC","territory_id":15,"territory_abbr":"CLT"},{"id":"06c15280da60ddfc62014894d5bd68a3dc374e0e3a6f360b76d3a5f022c580b0","posting_job_title":"Roofing Installation Crews","job_relationship":"company","location":"Charlotte, NC","territory_id":15,"territory_abbr":"CLT"}],
"NSH":[{"id":"624b363379c3963f804e170b02e39402322c27cd8da6ebac9861866530586d3a","posting_job_title":"Sales Representative*","job_relationship":"w2_employee","location":"Ashland City, TN","territory_id":16,"territory_abbr":"NSH"},{"id":"c44f268f5059e0b88652cb36e651ead19f0b7998deeec980dd52c7ca1ccdd1af","posting_job_title":"Entry Level Sales Representative*","job_relationship":"w2_employee","location":"Ashland City, TN","territory_id":16,"territory_abbr":"NSH"},{"id":"4c7f01b5e12adcfa38518d7687cd1201ec01c9b5b4cd621e3341fddedfab33cf","posting_job_title":"Entry Level Sales Representative*","job_relationship":"w2_employee","location":"Ashland City, TN","territory_id":16,"territory_abbr":"NSH"}],
"PHX":[{"id":"30afd9bf92825b4f69b0d57bdafd72f0cc054b135506a1236ce5eb54702694ad","posting_job_title":"Entry Level Sales Representative*","job_relationship":"w2_employee","location":"Glendale, AZ","territory_id":17,"territory_abbr":"PHX"},{"id":"5cf2990ca82ca1b2d43c40aa253458ce9cd05b0311a18ac39f7df274f99fb30d","posting_job_title":"Solar Sales Representative","job_relationship":"w2_employee","location":"Glendale, AZ","territory_id":17,"territory_abbr":"PHX"},{"id":"f9ca1b7db38430485feb0d285048527dd4fbf01c79fc43b47a1d6d9b270d9128","posting_job_title":"Sales Representative*","job_relationship":"w2_employee","location":"Glendale, AZ","territory_id":17,"territory_abbr":"PHX"}],
"PIT":[{"id":"be274ea74b2be7f448ddc28a1325957dad55b2a83dd0bc4141f8662965e641bc","posting_job_title":"Entry Level Sales Representative*","job_relationship":"w2_employee","location":"Chester, WV","territory_id":18,"territory_abbr":"PIT"},{"id":"9027f7f306b7d852ba544af54e0eb7956fdef5d17fd4d2cc619b8dba0ea45c79","posting_job_title":"Entry Level Sales Representative*","job_relationship":"w2_employee","location":"Chester, WV","territory_id":18,"territory_abbr":"PIT"},{"id":"331fd3928cc62352710e99070c3f91bc61ee72126deb121e55803e18a3bd9cc8","posting_job_title":"Entry Level Sales Representative*","job_relationship":"w2_employee","location":"Chester, WV","territory_id":18,"territory_abbr":"PIT"}]
}

The end goal is to take the above arrays and display each arrays' content so that:

  • each orange box would be a DIV
  • these will be coded as accordion toggles, where each territory_abbr can be opened to reveal each location and jobs available within each location
  • a total of 18 toggles (one for each territory_abbr)

enter image description here

Below is the code I have so far. I'm able to output majority of this correctly, but I can't figure out how to get the location value before each $value array in the code.

function display_jobs(){
    $jobs = get_jobs();

    //sort by territory_id and location
    usort($jobs, function($a, $b) { 
        return $a['territory_id'] <=> $b['territory_id'] ?: $a['location'] <=> $b['location'];
    });

    //group by location, display results.
    $group = array();
    foreach ($jobs as $posting) {
        $group[$posting['territory_abbr']][] = $posting;
    }

    $results .= "<div>"; // accordion
    $results .= "<div>"; // toggle
    
    //for each location
    foreach($group as $key=>$value){
            $results .= "<h3>" . $key . "</h3>"; // toggle title
        $results .= "<div>"; // toggle content
        $results .= "<h4>location name</h4>";
        $results .= "<div>";

        foreach ($value as $k=>$v) {
            //list posting_job_title for each location
            $results .= "<div>";
                $results .= "<ul class='col'>";
                    $results .= "<li>" . $v['territory_abbr'] . "</li>";
                    $results .= "<li>" . $v['territory_id'] . "</li>";
                    $results .= "<li>" . $v['location'] . "</li>";
                    $results .= "<li>" . $v['id'] . "</li>";
                    $results .= "<li>" . $v['posting_job_title'] . "</li>";
                    $results .= "<li>" . $v['job_relationship'] . "</li>";
                $results .= "</ul>";
            $results .= "</div>";
        }
        $results .= "</div>";
        $results .= "</div>";
    }


    $results .= "</div>";
    $results .= "</div>";
    return $results;
}

CodePudding user response:

Thanks to @Barmar, added another level of nesting of associative arrays, making location the key of these arrays.

Below is my updated code.

function display_jobs(){
    $jobs = get_jobs();

    //sort by territory_id and location
    usort($jobs, function($a, $b) { 
        return $a['territory_id'] <=> $b['territory_id'] ?: $a['location'] <=> $b['location'];
    });

    //group by location, display results.
    $group = array();
    foreach ($jobs as $posting) {
        $group[$posting['territory_abbr']][$posting['location']][] = $posting;
    }

    $results .= "<div>"; // accordion
    
    //for each territory_abbr
    foreach($group as $key=>$value){
        $results .= "<div>"; // toggle
        $results .= "<h3>" . $key . "</h3>"; // territory_abbr
        foreach($value as $k=>$v){
            $results .= "<div>"; // toggle content
            $results .= "<div>"; // extra wrapper
            $results .= "<h4 class='h5'>".$k."</h4>"; // location name
            foreach ($v as $k2=>$v2) {
                //list job info for each location
                $results .= "<div>";
                    $results .= "<ul class='col'>";
                            $results .= "<li>" . $v2['territory_abbr'] . "</li>";
                            $results .= "<li>" . $v2['territory_id'] . "</li>";
                            $results .= "<li>" . $v2['location'] . "</li>";
                            $results .= "<li>" . $v2['id'] . "</li>";
                            $results .= "<li>" . $v2['posting_job_title'] . "</li>";
                            $results .= "<li>" . $v2['job_relationship'] . "</li>";
                    $results .= "</ul>";
                $results .= "</div>";
            }
            $results .= "</div>";
            $results .= "</div>";
        }

        $results .= "</div>";

    }
    $results .= "</div>";
    return $results;
}
111

CodePudding user response:

To group rows of data in a 2d array by one column of data and maintain a 2d structure, nominate one column to be used as the first level keys and then push rows of data into the desired groups.

To group hierarchically on two column values, you must nominate first level and second level keys, then push data into the deep subset.

Sorting is best done when the input data is in its shallowest state.

When building your HTML string using concatenation, the variable must be declared as a string before using the concatenation assignment operator (.=).

The snippet below uses heredoc syntax to concatenate several of the HTML segments and border styling to improve the readability and maintainability of the script.

The sample input data in my demo link has been both reduced and made more complex in order to highlight the processing of differently sized groups in the 3d data structure.

Code: (Demo)

function display_jobs() {
    $jobs = get_jobs();

    usort($jobs, fn($a, $b) => 
        $a['territory_id'] <=> $b['territory_id']
        ?: $a['location'] <=> $b['location']
    );

    $groups = [];
    foreach ($jobs as $posting) {
        $groups[$posting['territory_abbr']][$posting['location']][] = $posting;
    }

    $html = '';
    foreach ($groups as $terrAbbr => $locations) {
        $html .= <<<HTML
            <div style="border: solid 1px orange;">
                <h3>$terrAbbr</h3>

        HTML;
            
        foreach ($locations as $locName => $postings) {
            $html .= <<<HTML
                    <div style="border: solid 1px blue;">
                        <h4>$locName</h4>

            HTML;

            foreach ($postings as $posting) {
                $html .= sprintf(<<<HTML
                                <div style="border: solid 1px green;">
                                    <ul >
                                        <li>%s</li>
                                        <li>%s</li>
                                        <li>%s</li>
                                        <li>%s</li>
                                        <li>%s</li>
                                        <li>%s</li>
                                    </ul>
                                </div>

                    HTML,
                    $posting['territory_abbr'],
                    $posting['territory_id'],
                    $posting['location'],
                    $posting['id'],
                    $posting['posting_job_title'],
                    $posting['job_relationship']
                );
            }
            $html .= <<<HTML
                    </div>

            HTML;
        }
        $html .= <<<HTML
            </div>

        HTML;
    }
    $html = $html ?: 'No data';
    return <<<HTML
    <div style="border: solid 1px red;">
    $html
    </div>
    HTML;
}
echo display_jobs();

Here is another answer of mine that demonstrates how to convert a 2d array into a 3d structure.

  • Related