Tanker
Tanker

Reputation: 1196

Use each delimited substring from a column of a 2d array and create grouped subarrays

Yes, this has been answered countless times by using different methods, in most cases it works but not on my case, please allow me to explain.

I'm building an array from a CSV file, that was the easy part, the difficult part is, I have is that I have to build another array from the first array grouping the results based on one key value, the problem is that this value is not an array, nor a simple string...
This is a sample from the array of the CSV file

[0] => Array
     (
       [key_1] => FOO
       [cats] => /30/
       [key_2] => FTU-1
     )
[1] => Array
     (
       [key_1] => FOO
       [cats] => /30/
       [key_2] => FTU-2
     )
[2] => Array
     (
       [key_1] => FOO
       [cats] => /30/10/
       [key_2] => FTU-3
     )
[3] => Array
     (
       [key_1] => FOO
       [cats] => /15/
       [key_2] => FTU-4
     )
[4] => Array
     (
       [key_1] => FOO
       [cats] => /10/
       [key_2] => FTU-5
     )
[0] => Array
     (
       [key_1] => FOO
       [cats] => /15/
       [key_2] => FTU-6
     )

The final array has to look like this based on the column cats:

[30] => Array 
        (
           [0] => Array 
                 (
                   [key_1] => FOO
                   [cats] => /30/
                   [key_2] => FTU-1
                 )
           [1] => Array
                 (
                   [key_1] => FOO
                   [cats] => /30/
                   [key_2] => FTU-2
                 )
           [1] => Array
                 (
                   [key_1] => FOO
                   [cats] => /30/10/
                   [key_2] => FTU-3
                 )
[15] => Array 
        (
           [0] => Array 
                 (
                   [key_1] => FOO
                   [cats] => /15/
                   [key_2] => FTU-4
                 )
           [1] => Array
                 (
                   [key_1] => FOO
                   [cats] => /15/
                   [key_2] => FTU-6
                 )
[10] => Array 
        (
           [0] => Array 
                 (
                   [key_1] => FOO
                   [cats] => /30/10/
                   [key_2] => FTU-3
                 )
           [1] => Array
                 (
                   [key_1] => FOO
                   [cats] => /10/
                   [key_2] => FTU-5
                 )

I was looking in to this This answer which is the closest to what I need, but didn't work, that's why I'm asking for help.

Update: I think I just solved it...

foreach($firstarr as $k => $v) {
  $cats = array_filter(explode('/', $v['cats']));
  foreach($cats as $ks=>$vs) {
    if(stripos($v['cats'], $vs)){
      $pp[$vs][] = $v;
    }
  }
}

looking good.

Upvotes: 1

Views: 123

Answers (4)

mickmackusa
mickmackusa

Reputation: 47894

Split the cats strings by the delimiting slashes and ignore empty element when looping. If there is no possibility of consecutive slashed then you can $cats = explode('/', trim($row['cats'], '/'));.

Use the individual cat values as first level keys and push the original row as a new subarray in the group.

Code: (Demo) (Alt Demo)

$result = [];
foreach ($array as $row) {
    $cats = preg_split('#/+#', $row['cats'], 0, PREG_SPLIT_NO_EMPTY); 
    foreach ($cats as $cat) {
        $result[$cat][] = $row;
    }
}
var_export($result);

Upvotes: 0

Poiz
Poiz

Reputation: 7617

This may be a twisted work-around but I am willing to bet it does the trick:

        <?php

        $arrResultant = array();

        foreach($arr as $intKey=>$arrData){
            $stripped   = preg_replace("#^\/#", "", $arrData['cats']);
            $arrParts   = preg_split("#\/#", $stripped);
            $intCat1    = isset($arrParts[0])? $arrParts[0]:null;
            $intCat2    = isset($arrParts[1])? $arrParts[1]:null;
            if(!array_key_exists($intCat1, $arrResultant)){
                $arrResultant[$intCat1] = array();
                if( stristr($arrData["cats"], $intCat1) ){
                    $arrResultant[$intCat1][] = $arrData;
                }
            }else{
                if( stristr( $arrData["cats"], $intCat1) ){
                    $arrResultant[$intCat1][] = $arrData;
                }
            }
            if(!array_key_exists($intCat2, $arrResultant) && !is_null($intCat2)){
                $arrResultant[$intCat2] = array();
                if( stristr($arrData["cats"], $intCat2) ){
                    $arrResultant[$intCat2][] = $arrData;
                }
            }else{
                if( stristr( $arrData["cats"], $intCat2) ){
                    $arrResultant[$intCat2][] = $arrData;
                }
            }
        }

        var_dump($arrResultant);

Try it out and let us know how it went....

Upvotes: 0

Maxim Tkach
Maxim Tkach

Reputation: 1697

Maybe you help this code:

function arrayByOneKey($array, $keyName)
{
    $result = [];
    foreach ($array as $item)
    {
        $keys = explode('/', (string)$item[$keyName]);
        foreach($keys as $key)
        {
            if($key == '')
            {
                continue;
            }
            $result[$key][] = $item;
        }
    }
    return $result;
}

$array = [
    [
        'key_1' => 'FOO',
        'key_2' => 'FTU-1',
        'cats' => '/15/'
    ],
    [
        'key_1' => 'FOO',
        'key_2' => 'FTU-2',
        'cats' => '/15/'
    ],
    [
        'key_1' => 'FOO',
        'key_2' => 'FTU-3',
        'cats' => '/30/10/'
    ],
    [
        'key_1' => 'FOO',
        'key_2' => 'FTU-4',
        'cats' => '/30/10/0'
    ]
];

$array = arrayByOneKey($array, 'cats');
var_dump($array);

Result:

array(4) {
  [15]=>
  array(2) {
    [0]=>
    array(3) {
      ["key_1"]=>
      string(3) "FOO"
      ["key_2"]=>
      string(5) "FTU-1"
      ["cats"]=>
      string(4) "/15/"
    }
    [1]=>
    array(3) {
      ["key_1"]=>
      string(3) "FOO"
      ["key_2"]=>
      string(5) "FTU-2"
      ["cats"]=>
      string(4) "/15/"
    }
  }
  [30]=>
  array(2) {
    [0]=>
    array(3) {
      ["key_1"]=>
      string(3) "FOO"
      ["key_2"]=>
      string(5) "FTU-3"
      ["cats"]=>
      string(7) "/30/10/"
    }
    [1]=>
    array(3) {
      ["key_1"]=>
      string(3) "FOO"
      ["key_2"]=>
      string(5) "FTU-4"
      ["cats"]=>
      string(8) "/30/10/0"
    }
  }
  [10]=>
  array(2) {
    [0]=>
    array(3) {
      ["key_1"]=>
      string(3) "FOO"
      ["key_2"]=>
      string(5) "FTU-3"
      ["cats"]=>
      string(7) "/30/10/"
    }
    [1]=>
    array(3) {
      ["key_1"]=>
      string(3) "FOO"
      ["key_2"]=>
      string(5) "FTU-4"
      ["cats"]=>
      string(8) "/30/10/0"
    }
  }
  [0]=>
  array(1) {
    [0]=>
    array(3) {
      ["key_1"]=>
      string(3) "FOO"
      ["key_2"]=>
      string(5) "FTU-4"
      ["cats"]=>
      string(8) "/30/10/0"
    }
  }
}

UPDATE

array_filter - elegant solution BUT category with id 0 will be ignored. And if so, then !empty($key) In the cycle better than array_filter - as it also passes through the array elements

Upvotes: 1

Fabricator
Fabricator

Reputation: 12772

You can get the key from explode('/', $item['cats'])[1]:

$newArray = [];
foreach($originalArray as $item) {
    $key = explode('/', $item['cats'])[1];
    $newArray[$key][] = $item;
}

Upvotes: 0

Related Questions