【问题标题】:Preserve elements in each row of a two-dimensional array based on another array基于另一个数组保留二维数组的每一行中的元素
【发布时间】:2019-03-13 08:49:21
【问题描述】:

我有这个数组:

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 不是一个选项,因为它只给我一列)。

我做了什么

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

问题是它看起来太滞后,因为它在这个上迭代了两次。 如果没有这种解决方法,有没有办法获得多个列?

我正在使用 PHP5.6

【问题讨论】:

  • 嗨@fiskolin,问题不清楚
  • @fiskolin 你能解释一下你从哪里得到数组吗?是否可以修改数据的初始拉取?
  • 更大的问题是你丢失了钥匙,Sandbox

标签: php arrays filtering php-5.6


【解决方案1】:

如果我正确理解您的问题,您可以尝试传统的 foreach - 它可能会快一点。

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

(未测试)

问题是它看起来太迟钝了,因为它在这个上迭代了两次

您的原始代码没有在同一个数组上迭代两次。如果你想要一个数组,其中每个元素都是另一个元素数组,其中的键来自 filterKeys 数组,你将无法绕过迭代主数组和 filterKeys 数组。

【讨论】:

    【解决方案2】:

    我将 @Chayan 中的优雅方法重构为一个函数,因此它可以像 array_column() 一样使用。现在可以将要过滤的键表示为一个简单的数组。

    顺便说一句,这很可能也是最快的方法,因为它使用内置函数来完成大部分繁重的工作。

    function array_columns(array $arr, array $keysSelect)
    {    
        $keys = array_flip($keysSelect);
        return array_map(
            function($a) use($keys) {
                return array_intersect_key($a,$keys);
            },
            $arr
        );
    }
    
    $arr = [
        [
            "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 = ["product_id" , "product_sku"];
    $filteredArray = array_columns($arr, $keysSelect);
    
    var_dump($filteredArray);
    

    【讨论】:

      【解决方案3】:

      array_columns 函数的新增功能最终追溯到 Chayan 的答案,这次是从 Joseph Mangion 的函数扩展而来。

      我偶尔会有很长的选定列列表,我想在其中保留键,并且不一定要为大量字段遵循繁琐的 ['orignal_field_name'] => ['original_field_name'] 格式。

      此版本默认保留每个字段的原始键,除非指定新键。

      // See answer from Joseph Mangion: https://stackoverflow.com/questions/52706383/php-get-multiple-columns-from-array
      /** Function - array_columns  Selects columns from multidimensional array and renames columns as required
      *
      * @param  array $in_array, array $select_columns_rename_keys
      *   example of $select_columns_rename_keys:
      *       ['new_column_name1' => 'original_column_name1', 'original_column_name2', 'original_column_name3', 'new_column_name4' => 'original_column_name4', ...]
      *       This will use the original keys for columns 2 and 3 and rename columns 1 and 4
      * @return array
      * @access public
      * 
      */   
      
      public function array_columns($in_array, $select_columns_rename_keys) {
          foreach ($select_columns_rename_keys as $k => $v)
              if (is_int($k)) {
                  $select_columns_rename_keys[$v] = $v;
                  unset($select_columns_rename_keys[$k]);
              }
          $keys = array_flip($select_columns_rename_keys);
          $filtered_array =
              array_map(function($a) use($keys) {
              $data = array_intersect_key($a, $keys);
              $return_array = [];
              foreach ($data as $column_name => $value) $return_array[$keys[$column_name]] = $value;
              return $return_array;
          }, $in_array);
      
          return $filtered_array;
      }
      

      【讨论】:

        【解决方案4】:

        这是一个基于 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;
        }
        

        【讨论】:

          【解决方案5】:

          如果您不想更改原始数组并想要所需的输出

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

          【讨论】:

          • 真正干净的解决方案,你也可以使用array_flip()获取数组值作为过滤的键!
          【解决方案6】:

          我认为更大的问题是你丢失了钥匙

          Original Code

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

          您可以使用简单的 foreach 代替第二个 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);
          }
          

          输出

          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

          问题是它看起来太迟钝了,因为它在这个上迭代了两次。

          没有不迭代两次的真正方法,但您可能也不想扔掉密钥。

          也就是说你可以递归地取消设置你不想要的项目。

          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 并查看。

          Sandbox

          最后一点,您不应该假设键存在或键将是一个数组,除非您键入强制转换为数组。

          你也可以用数组过滤器来做

          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) 有一些小的性能优势。

          Sandbox

          【讨论】:

            【解决方案7】:

            如果您需要数组中的两列,其中一列是 SKU(通常是唯一的),那么您可以将 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

            【讨论】:

            • 这是另一个问题的正确答案。它没有提供问题中所要求的结果。 (这并不是说这是一种不好的技术;它只是偏离了要求。)
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2021-03-15
            • 2019-12-08
            • 1970-01-01
            • 2016-12-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多