web-dev-qa-db-ja.com

PHP-配列から複数の列を取得

私はこの配列を持っています:

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

私が探しているのは、必要な列のみを含む複数の配列を取得する方法です(array_columnは1列しかないため、オプションではありません)。

私がやったこと

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

問題はlaggyであるように見えることです。これはこれを2回繰り返すためです。この回避策なしで複数の列を取得する方法はありますか? PHP:5.6

6
fiskolin

より大きな問題はあなたが鍵を失うことだと思います

元のコード

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

2番目のarray_mapの代わりに単純なforeachを使用できます:

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

出力

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',
  ),
)

サンドボックス

問題は、これを2回繰り返すため、時間がかかりすぎるように見えることです。

2回繰り返さないようにする実際の方法はありませんが、おそらくキーも捨てたくないでしょう。

つまり、不要な項目の設定を再帰的に解除できます。

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

以前と同じ出力

これは参照することで簡単になります。どちらかと言えば、2つをテストして確認する必要があります。

サンドボックス

最後に、キーを配列としてキャストしない限り、キーが存在する、またはそのキーが配列になると想定しないでください。

配列フィルターでそれを行うこともできます

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

ループの外側でフィルタリングするための関数(array_map)を宣言すると、パフォーマンスが少し向上します。

サンドボックス

2
ArtisticPhoenix

1つがSKU(通常は一意)である配列から2つの列が必要な場合は、3番目のパラメーターでarray_columnを使用できます。

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

これにより、SKUをキーとして、IDを値として持つフラット配列が返され、配列も扱いやすくなります。

出力:

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

https://3v4l.org/UDGiO

1
Andreas

@Chayanからのエレガントなアプローチを関数にリファクタリングして、array_column()のように使用できるようにしました。フィルタリングされるキーは、単純な配列として提示できるようになりました。

ところで、これは最も重いアプローチのほとんどに組み込み関数を使用するため、おそらく最も速いアプローチでもあります。

<?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

私があなたの質問を正しく理解していれば、従来のforeachを試すことができます-少し速いかもしれません。

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

(未検証)

問題は、これを2回繰り返すため、遅すぎるように見えることです

元のコードが同じ配列で2回繰り返されていません。各要素がfilterKeys配列のキーを持つ要素の別の配列である配列が必要な場合は、メイン配列を繰り返し処理してからfilterKeys配列を回避することはできません。

1
Nathan

これは、選択された列の名前変更が追加されたChayanに基づくリファクタリングされた関数です。


 /** 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

元の配列を変更せず、希望の出力が必要な場合

array_insersect_key 関数を使用して、次のように目的の出力を取得します

$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