Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Preserve elements in each row of a two-dimensional array based on another array

I have this array:

0 => array:3 [
    "product_id" => "1138"
    "product_image" => "/resources/medias/shop/products/shop-6500720--1.png"
    "product_sku" => "6500722"
  ]
1 => array:3 [
    "product_id" => "1144"
    "product_image" => "/resources/medias/shop/products/shop-6501041--1.png"
    "product_sku" => "6501046"
  ]
2 => array:3 [
    "product_id" => "113"
    "product_image" => "/resources/medias/shop/products/shop-6294909--1.png"
    "product_sku" => "6294915"
]

What I am looking for is a way to get a multiple array with only required columns (array_column is not a option, since it's give me only 1 column).

What I have done

function colsFromArray($array, $keys)
{
    return array_map(function ($el) use ($keys) {
        return array_map(function ($c) use ($el) {
            return $el[$c];
        }, $keys);
    }, $array);
}

$array = array(
    [
        "product_id"    => "1138",
        "product_image" => "/resources/medias/shop/products/shop-6500720--1.png",
        "product_sku"   => "6500722"
    ],
    [
        "product_id"    => "1144",
        "product_image" => "/resources/medias/shop/products/shop-6501041--1.png",
        "product_sku"   => "6501046"
    ],
    [
        "product_id"    => "113",
        "product_image" => "/resources/medias/shop/products/shop-6294909--1.png",
        "product_sku"   => "6294915"
    ]
);
colsFromArray($array, array("product_id", "product_sku"));

//0 => array:3 [
//    "product_id" => "1138"
//    "product_sku" => "6500722"
//  ]
//1 => array:3 [
//    "product_id" => "1144"
//    "product_sku" => "6501046"
//  ]
//2 => array:3 [
//    "product_id" => "113"
//    "product_sku" => "6294915"
//]

The problem is that it seems too laggy, since it iterates twice over this. Is there any way to get multiple columns without this workaround?

I'm using PHP5.6

like image 917
fiskolin Avatar asked Oct 08 '18 16:10

fiskolin


1 Answers

I think the bigger issue is you lose the keys

Original Code

array (
  0 => 
  array (
    0 => '1138',
    1 => '6500722',
  ),
  1 => 
  array (
    0 => '1144',
    1 => '6501046',
  ),
  2 => 
  array (
    0 => '113',
    1 => '6294915',
 );

You can use a simple foreach instead of the second array_map:

function colsFromArray(array $array, $keys)
{
    if (!is_array($keys)) $keys = [$keys];
    return array_map(function ($el) use ($keys) {
        $o = [];
        foreach($keys as $key){
            //  if(isset($el[$key]))$o[$key] = $el[$key]; //you can do it this way if you don't want to set a default for missing keys.
            $o[$key] = isset($el[$key])?$el[$key]:false;
        }
        return $o;
    }, $array);
}

Output

array (
  0 => 
  array (
    'product_id' => '1138',
    'product_sku' => '6500722',
  ),
  1 => 
  array (
    'product_id' => '1144',
    'product_sku' => '6501046',
  ),
  2 => 
  array (
    'product_id' => '113',
    'product_sku' => '6294915',
  ),
)

Sandbox

the problem is that it seems too laggy, since it iterates twice over this.

There is no real way to not iterate over it 2 times, but you probably don't want to throw away the keys either.

That said you can recursively unset the items you don't want.

function colsFromArray(array &$array, $keys)
{
    if (!is_array($keys)) $keys = [$keys];
    foreach ($array as $key => &$value) {
        if (is_array($value)) {
            colsFromArray($value, $keys); //recursive
        }else if(!in_array($key, $keys)){
           unset($array[$key]); 
        }
    }
}

colsFromArray($array, array("product_id", "product_sku"));
var_export($array);

Same output as before

This is easier to do by reference. Rather or not that is faster you'll have to test the 2 and see.

Sandbox

As a final note you shouldn't assume the key will exist or that keys will be an array unless you type cast it as an array.

You could also do it with array filter

function colsFromArray(array $array, $keys)
{
    if (!is_array($keys)) $keys = [$keys];
    $filter = function($k) use ($keys){
       return in_array($k,$keys);
    };
    return array_map(function ($el) use ($keys,$filter) {
        return array_filter($el, $filter, ARRAY_FILTER_USE_KEY );
    }, $array);
}

There is some small performance benefit to declaring the function for filtering outside of the loop (array_map).

Sandbox

like image 138
ArtisticPhoenix Avatar answered Oct 15 '22 23:10

ArtisticPhoenix