web-dev-qa-db-fra.com

PHP - récupère plusieurs colonnes du tableau

J'ai ce tableau:

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"
]

Ce que je recherche, c'est un moyen d'obtenir un tableau multiple avec uniquement les colonnes requises (array_column n'est pas une option, car il ne me donne qu'une seule colonne).

Ce que j'ai fait

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"
//]

Le problème est qu'il semble trop décalé , car il répète deux fois cela. Est-il possible d'obtenir plusieurs colonnes sans cette solution de contournement? PHP: 5,6

6
fiskolin

Je pense que le plus gros problème est que vous perdez les clés

Code d'origine

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

Vous pouvez utiliser un simple foreach au lieu du 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);
}

Production

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

le problème est qu'il semble trop lent, car il réitère deux fois ce point.

Il n'y a pas vraiment de moyen de ne pas le répéter 2 fois, mais vous ne voulez probablement pas non plus jeter les clés.

Cela dit, vous pouvez annuler récursivement les éléments dont vous ne voulez pas.

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);

Même sortie qu'avant

C'est plus facile à faire par référence. Plutôt ou non, c'est plus rapide, vous devrez tester les 2 et voir.

Sandbox

En guise de note finale, vous ne devez pas supposer que la clé existera ou que les clés seront un tableau à moins que vous ne les transposiez en tableau.

Vous pouvez également le faire avec un filtre matriciel

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);
}

Il y a un petit avantage en termes de performances à déclarer la fonction de filtrage en dehors de la boucle (array_map).

Sandbox

2
ArtisticPhoenix

Si vous avez besoin de deux colonnes d'un tableau dont l'un est SKU (qui est généralement unique), vous pouvez utiliser array_column avec le troisième paramètre.

$new = array_column($arr, "product_id", "product_sku");

Cela renverra un tableau plat avec le SKU comme clé et l'ID comme valeur, ce qui rendra le tableau facile à utiliser également.

Production:

array(3) {
  [6500722]=>
  string(4) "1138"
  [6501046]=>
  string(4) "1144"
  [6294915]=>
  string(3) "113"
}

https://3v4l.org/UDGiO

1
Andreas

J'ai refactorisé l'approche élégante de @Chayan dans une fonction afin qu'elle puisse être utilisée comme array_column(). Les clés à filtrer peuvent désormais être présentées comme un simple tableau.

C'est probablement aussi l'approche la plus rapide, car elle utilise des fonctions intégrées pour la plupart des travaux lourds.

<?php

function array_columns(array $arr, array $keysSelect)
{    
    $keys = array_flip($keysSelect);
    $filteredArray = array_map(function($a) use($keys){
        return array_intersect_key($a,$keys);
    }, $arr);

    return $filteredArray;
}

$arr = 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"
    ]
);

$keysSelect = array("product_id" , "product_sku");
$filteredArray = array_colums($arr, $keysSelect);

var_dump($filteredArray);
1
Erik Kalkoken

Si je comprends bien votre question, vous pouvez essayer une foreach traditionnelle - elle pourrait être un peu plus rapide.

function colsFromArray($array, $filterKeys) {
    $newArr = [];
    foreach($array as $key => $val) {
       $element = [];
       foreach($filterKeys as $filterKey) {
          $element[$filterKey] = $val[$filterKey];
       }
       $newArr[] = $element;
    }
}

(Pas testé)

Le problème est qu'il semble trop lent, car il répète deux fois cette

Votre code d'origine n'itère pas deux fois sur le même tableau. Vous ne pourrez pas contourner le tableau principal puis le tableau filterKeys si vous voulez avoir un tableau où chaque élément est un autre tableau d'éléments avec des clés du tableau filterKeys.

1
Nathan

Il s'agit d'une fonction refactorisée basée sur celle de Chayan avec un renommage supplémentaire des colonnes sélectionnées:


 /** Function - array_columns  Selects columns from multidimantional array and renames columns as required
 *
 * @param  array $arr, array $selectColRenameKeys 
 *            example: (NewName1->colNameneeded1,NewName2->colNameneeded2,ect...)
 * @return array
 * @access public
 * 
 */   

 private function array_columns( $arr,$selectColRenameKeys) {    
    $keys = array_flip($selectColRenameKeys);
    $filteredArray = array_map(function($a) use($keys){
                                  $data = array_intersect_key($a,$keys);
                                  $rename_arr= array();
                                  foreach ($data as $colname => $value){
                                    $r_arr[$keys[$colname]]= $value   ;
                                  }
                                  return $r_arr;
                               }, $arr);

    return $filteredArray;
}
0
Joseph Mangion

Si vous ne souhaitez pas modifier votre matrice d'origine et souhaitez obtenir la sortie souhaitée

Utilisez la fonction array_insersect_key pour obtenir la sortie souhaitée comme suit

$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"
    ]
);

$keys = array("product_id"=>1, "product_sku"=>2);

$filteredArray = array_map(function($a) use($keys){
    return array_intersect_key($a,$keys);
}, $array);

print_r($filteredArray);
0
Chayan