【问题标题】:In PHP, is there a function that returns an array made up of the value of a key from an array of associative arrays?在 PHP 中,是否有一个函数可以返回由关联数组数组中的键值组成的数组?
【发布时间】:2012-05-26 10:56:10
【问题描述】:

我确定这个问题以前有人问过,很抱歉没有先找到它。

原始数组:

[0] => Array
    (
        [categoryId] => 1
        [eventId] => 2
        [eventName] => 3
        [vendorName] => 4
    )

[1] => Array
    (
        [categoryId] => 5
        [eventId] => 6
        [eventName] => 7
        [vendorName] => 8
    )

[2] => Array
    (
        [categoryId] => 9
        [eventId] => 10
        [eventName] => 11
        [vendorName] => 12
    )

我希望的结果来自:print_r(get_values_from_a_key_in_arrays('categoryId', $array));

[0] => 1
[1] => 5
[2] => 9

我只是在寻找比编写自己的基于 foreach 的函数更干净的东西。如果 foreach 是答案,我已经准备好了。

编辑:我不想使用硬编码的密钥,我只是展示了一个对解决方案的调用示例。谢谢! ^_^

PHP 5.3 的快速抓取解决方案:

private function pluck($key, $data) {
    return array_reduce($data, function($result, $array) use($key) {
        isset($array[$key]) && $result[] = $array[$key];
        return $result;
    }, array());
}

【问题讨论】:

  • 这被称为plucking,不是默认的 PHP 函数。不过,您可以轻松地自己编写。
  • 真的很酷。我以前做过,但我从来不知道它的技术名称是plucking
  • 这很好,但array_reduce() 是错误的函数。它旨在“将数组减少为单个值”。在其他语言中也是如此。您应该使用array_map()array_walk() 重写...这也将简化代码。
  • @doublejosh 我不同意。 array_reduce 在这里很好。它将数组数组简化为值数组。
  • 内层操作确实是reduce,我在抱怨使用的时候肯定是看外层操作了。

标签: php arrays associative-array array-reduce pluck


【解决方案1】:

对此没有内置函数,但通常称为“pluck”。

【讨论】:

  • 从 PHP 5.5 开始,有一个内置的:array_column
【解决方案2】:
<?php
$a = array(
        array('a' => 1, 'b' => 2),
        array('a' => 2, 'b' => 2),
        array('a' => 3, 'b' => 2),
        array('a' => 4, 'b' => 2)
);

function get_a($v) {
        return $v['a'];
}

var_dump(array_map('get_a', $a));

您可以使用 create_function 或匿名函数 (PHP 5.3 >=)

<?php
$a = array(
        array('a' => 1, 'b' => 2),
        array('a' => 2, 'b' => 2),
        array('a' => 3, 'b' => 2),
        array('a' => 4, 'b' => 2)
);

var_dump(array_map(create_function('$v', 'return $v["a"];'), $a));

如上所述,我会编写一个回调函数,然后将它与 array_map 一起使用。

【讨论】:

  • 如果您使用的是 PHP5.3 或更高版本,您可以将get_a 写为 lambda 函数,并使其更加紧凑。 (编辑......因为我注意到其他答案正在做)
  • @Spudley:看我的回答,它完全按照你提到的方式。
  • @Tadeck - 是的,我看到了(并给了你+1),但只有在我先评论了这个答案之后。
  • create_function 很烂,它在 PHP 5.3 之前可用。
【解决方案3】:

您可以使用array_filter,并根据所需键传入一个函数。

不过,Tadeck 的回答要好得多。

【讨论】:

    【解决方案4】:

    没有内置函数。但是使用array_map() 很容易制作。

    $array = array(
        array(
            "categoryID"   => 1,
            "CategoryName" => 2,
            "EventName"    => 3,
            "VendorName"   => 4
        ),
        array(
            "categoryID"   => 5,
            "CategoryName" => 6,
            "EventName"    => 7,
            "VendorName"   => 8
        ),
        array(
            "categoryID"   => 9,
            "CategoryName" => 10,
            "EventName"    => 11,
            "VendorName"   => 12
        )
    );
    
    $newArray = array_map(function($el) {
        return $el["categoryID"];
    }, $array);
    
    var_dump($newArray);
    

    【讨论】:

      【解决方案5】:

      映射是你所需要的:

      $input = array(
          array(
              'categoryId' => 1,
              'eventId' => 2,
              'eventName' => 3,
              'vendorName' => 4,
          ),
          array(
              'categoryId' => 5,
              'eventId' => 6,
              'eventName' => 7,
              'vendorName' => 8,
          ),
          array(
              'categoryId' => 9,
              'eventId' => 10,
              'eventName' => 11,
              'vendorName' => 12,
          ),
      );
      
      $result = array_map(function($val){
          return $val['categoryId'];
      }, $input);
      

      或者创建一个你想要的函数:

      function get_values_from_a_key_in_arrays($key, $input){
          return array_map(function($val) use ($key) {
              return $val[$key];
          }, $input);
      };
      

      然后使用它:

      $result = get_values_from_a_key_in_arrays('categoryId', $array);
      

      它将在 PHP >= 5.3 中工作,其中允许匿名回调。对于早期版本,您需要提前定义回调并传递其名称而不是匿名函数。

      【讨论】:

      • 你能把return $val['categoryId'];变成return $val[$key];吗?
      • @Songo:如果不创建一个由count($input)$key 值组成的数组,一种解决方案是array_map(function($val, $key = 'categoryId') {return $val[$key];}, $input)——但我看不出在 lambda 中这样做有什么好处功能。
      • @Songo:另一种解决方案是:array_map(function($val, $key) {return $val[$key];}, $input, array_fill(0, count($input), 'categoryId'))
      • @Songo:我已经完全按照 OP 的要求添加了一个功能,所以你应该满意 ;)
      • 不要使用 create_function(),如果不希望 array_map() 带有匿名函数:而是使用循环(无论如何这将比调用地图回调“更快”)。
      【解决方案6】:

      所以,higher-ordercollection/iterator functionspluckfiltereachmap 和朋友们的酷之处在于它们可以混合和匹配以组成更复杂的集合操作。

      大多数语言都提供这些类型的函数(查找诸如集合、迭代器或枚举/可枚举的包)...有些提供的函数比其他的多,而且您通常会看到函数在不同语言中的命名方式不同(即 collect = =地图,减少==折叠)。如果一个函数 doesn't exist in your language, you can create it 来自确实存在的函数。

      至于你的测试用例...我们可以使用array_reduce 来实现pluck。我发布的第一个版本依赖于array_map;但是,我同意@salathe 的观点,即array_reduce 更简洁地完成这项任务; array_map 是一个不错的选择,但最终你不得不做更多的工作。 array_reduce 乍一看可能有点奇怪,但如果回调组织得井井有条,一切都很好。

      不那么天真的pluck 还会检查它是否可以“调用”(函数/方法)迭代值。在下面的简单实现中,我们假设结构是一个哈希(关联数组)。

      这将设置测试用例数据(Fixtures):

      <?php
      
      $data[] = array('categoryId' => 1,    'eventId' => 2,  'eventName' => 3,  'vendorName' => 4);
      $data[] = array('categoryId' => 5,    'eventId' => 6,  'eventName' => 7,  'vendorName' => 8);
      $data[] = array('categoryId' => 9,    'eventId' => 10, 'eventName' => 11, 'vendorName' => 12);
      $data[] = array(/* no categoryId */   'eventId' => 10, 'eventName' => 11, 'vendorName' => 12);
      $data[] = array('categoryId' => false,'eventId' => 10, 'eventName' => 11, 'vendorName' => 12);
      $data[] = array('categoryId' => 0.0,  'eventId' => 10, 'eventName' => 11, 'vendorName' => 12);
      

      选择您喜欢的 pluck 版本

      $preferredPluck = 'pluck_array_reduce'; // or pluck_array_map
      

      PHP 5.3+ 的“pluck”:array_reduce 提供了一个简洁的实现,但不像 array_map 版本那么容易推理:

      function pluck_array_reduce($key, $data) {
        return array_reduce($data, function($result, $array) use($key){
          isset($array[$key]) &&
            $result[] = $array[$key];
      
          return $result;
        }, array());
      }
      

      “pluck”适用于 PHP 5.3+:array_map 并不完美,因此我们必须进行更多检查(它仍然无法解决许多潜在情况):

      function pluck_array_map($key, $data) {
        $map = array_map(function($array) use($key){
          return isset($array[$key]) ? $array[$key] : null;
        }, $data);
      
        // is_scalar isn't perfect; to make this right for you, you may have to adjust
        return array_filter($map, 'is_scalar');
      }
      

      “pluck”用于旧版 PHP

      我们本可以使用旧版create_function;但是,它的形式很糟糕,不推荐,而且一点也不优雅,因此,我决定不展示它。

      function pluck_compat($key, $data) {
        $map = array();
        foreach ($data as $array) {
          if (array_key_exists($key, $array)) {
            $map[] = $array[$key];
          }
        }
        unset($array);
      
        return $map;
      }
      

      这里我们根据我们正在运行的 PHP 版本选择一个“pluck”版本来调用。如果你运行整个脚本,无论你使用什么版本,你都应该得到正确的答案。

      $actual   = version_compare(PHP_VERSION, '5.3.0', '>=')
                ? $preferredPluck('categoryId', $data)
                : pluck_compat('categoryId', $data);
      $expected = array(1, 5, 9, false, 0.0);
      $variance = count(array_diff($expected, $actual));
      
      var_dump($expected, $actual);
      echo PHP_EOL;
      echo 'variance: ', $variance, PHP_EOL;
      
      print @assert($variance)
          ? 'Assertion Failed'
          : 'Assertion Passed';
      

      注意没有结尾'?>'。那是因为不需要它。离开它比保留它带来更多好处。

      FWIW,看起来这是作为 array_column 添加到 PHP 5.5 中的。

      【讨论】:

      • 哇,这是什么版本的 PHP?我从未见过“使用”,这太棒了。
      • 在 PHP 5.3 中引入匿名函数(lambda 和闭包)时提供了使用:php.net/functions.anonymous
      • 为了其他人发现这一点,您介意使用 create_function,并将 array_map 放在 array_filter 调用中(摆脱 $map 变量)吗?
      • P.S.映射/过滤步骤可以与array_reduce() 合二为一。
      • 嗨@salathe;你提出了一个很好的观点。我几乎用 array_reduce() 完成了我的原始实现;但是,我通常将 array_reduce 保留用于无法用其他方法轻松处理的情况。 array_reduce 很棒;但是,推理需要更多的认知开销。
      【解决方案7】:

      当您需要 lisp 时,它在哪里?实际上在 php 中它也很容易管理。只需使用 array_map 函数,如下图所示。

      # bunch o data
      $data = array();
      $data[0] = array("id" => 100, "name" => 'ted');
      $data[1] = array("id" => 200, "name" => 'mac');
      $data[2] = array("id" => 204, "name" => 'bub');
      
      # what you want to do to each bit of it
      function pick($n) { return($n['id']); }
      # what you get after you do that
      $map = array_map("pick", $data);
      # see for yourself
      print_r($map);
      

      【讨论】:

        【解决方案8】:

        从 PHP 5.5 开始,使用 array_column:

        $events = [
            [ 'categoryId' => 1, 'eventId' =>  2, 'eventName' =>  3, 'vendorName' =>  4 ],
            [ 'categoryId' => 5, 'eventId' =>  6, 'eventName' =>  7, 'vendorName' =>  8 ],
            [ 'categoryId' => 9, 'eventId' => 10, 'eventName' => 11, 'vendorName' => 12 ],
        ];
        
        print_r(array_column($events, 'categoryId'));
        

        See it online at 3v4l.

        对于 5.5 之前的版本,您可以考虑使用 polyfill

        【讨论】:

          猜你喜欢
          • 2015-07-23
          • 2011-10-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多