array_column()
(PHP 5 >= 5.5.0, PHP 7)
返回数组中指定的一列
说明
array_column(array $input,mixed $column_key[,mixed $index_key= null]): array
array_column()返回$input数组中键值为$column_key的列,如果指定了可选参数$index_key,那么$input数组中的这一列的值将作为返回数组中对应值的键。
参数
- $input
需要取出数组列的多维数组。如果提供的是包含一组对象的数组,只有 public 属性会被直接取出。为了也能取出 private 和 protected 属性,类必须实现__get()和__isset()魔术方法。
- $column_key
需要返回值的列,它可以是索引数组的列索引,或者是关联数组的列的键,也可以是属性名。也可以是
NULL
,此时将返回整个数组(配合$index_key参数来重置数组键的时候,非常管用)- $index_key
作为返回数组的索引/键的列,它可以是该列的整数索引,或者字符串键值。
返回值
从多维数组中返回单列数组。
更新日志
版本 | 说明 |
---|---|
7.0.0 | $input参数现在可以是包含对象的数组。 |
范例
从结果集中取出first names列
<?php // Array representing a possible record set returned from a database $records = array( array( 'id' => 2135, 'first_name' => 'John', 'last_name' => 'Doe', ), array( 'id' => 3245, 'first_name' => 'Sally', 'last_name' => 'Smith', ), array( 'id' => 5342, 'first_name' => 'Jane', 'last_name' => 'Jones', ), array( 'id' => 5623, 'first_name' => 'Peter', 'last_name' => 'Doe', ) ); $first_names = array_column($records, 'first_name'); print_r($first_names); ?>
以上例程会输出:
Array ( [0] => John [1] => Sally [2] => Jane [3] => Peter )
从结果集中总取出last names列,用相应的id作为键值
<?php // Using the $records array from Example #1 $last_names = array_column($records, 'last_name', 'id'); print_r($last_names); ?>
以上例程会输出:
Array ( [2135] => Doe [3245] => Smith [5342] => Jones [5623] => Doe )
username 列是从对象获取 public 的"username"属性
<?php class User { public $username; public function __construct(string $username) { $this->username = $username; } } $users = [ new User('user 1'), new User('user 2'), new User('user 3'), ]; print_r(array_column($users, 'username')); ?>
以上例程会输出:
Array ( [0] => user 1 [1] => user 2 [2] => user 3 )
获取 username 列,从对象通过魔术方法__get()获取 private 的"username"属性。
<?php class Person { private $name; public function __construct(string $name) { $this->name = $name; } public function __get($prop) { return $this->$prop; } public function __isset($prop) : bool { return isset($this->$prop); } } $people = [ new Person('Fred'), new Person('Jane'), new Person('John'), ]; print_r(array_column($people, 'name')); ?>
以上例程会输出:
Array ( [0] => Fred [1] => Jane [2] => John )如果不提供__isset(),会返回空数组。
参见
- » Recommended userland implementation for PHP lower than 5.5
if array_column does not exist the below solution will work. if(!function_exists("array_column")) { function array_column($array,$column_name) { return array_map(function($element) use($column_name){return $element[$column_name];}, $array); } }
Because the function was not available in my version of PHP, I wrote my own version and extended it a little based on my needs. When you give an $indexkey value of -1 it preserves the associated array key values. EXAMPLE: $sample = array( 'test1' => array( 'val1' = 10, 'val2' = 100 ), 'test2' => array( 'val1' = 20, 'val2' = 200 ), 'test3' => array( 'val1' = 30, 'val2' = 300 ) ); print_r(array_column_ext($sample,'val1')); OUTPUT: Array ( [0] => 10 [1] => 20 [2] => 30 ) print_r(array_column_ext($sample,'val1',-1)); OUTPUT: Array ( ['test1'] => 10 ['test2'] => 20 ['test3'] => 30 ) print_r(array_column_ext($sample,'val1','val2')); OUTPUT: Array ( [100] => 10 [200] => 20 [300] => 30 ) <?php function array_column_ext($array, $columnkey, $indexkey = null) { $result = array(); foreach ($array as $subarray => $value) { if (array_key_exists($columnkey,$value)) { $val = $array[$subarray][$columnkey]; } else if ($columnkey === null) { $val = $value; } else { continue; } if ($indexkey === null) { $result[] = $val; } elseif ($indexkey == -1 || array_key_exists($indexkey,$value)) { $result[($indexkey == -1)?$subarray:$array[$subarray][$indexkey]] = $val; } } return $result; } ?>
You can also use array_map fucntion if you haven't array_column(). example: $a = array( array( 'id' => 2135, 'first_name' => 'John', 'last_name' => 'Doe', ), array( 'id' => 3245, 'first_name' => 'Sally', 'last_name' => 'Smith', ) ); array_column($a, 'last_name'); becomes array_map(function($element){return $element['last_name'];}, $a);
This function does not preserve the original keys of the array (when not providing an index_key). You can work around that like so: <?php // instead of array_column($array, 'column'); // to preserve keys array_combine(array_keys($array), array_column($array, 'column')); ?>
Some remarks not included in the official documentation. 1) array_column does not support 1D arrays, in which case an empty array is returned. 2) The $column_key is zero-based. 3) If $column_key extends the valid index range an empty array is returned.
<?php # for PHP < 5.5 # AND it works with arrayObject AND array of objects if (!function_exists('array_column')) { function array_column($array, $columnKey, $indexKey = null) { $result = array(); foreach ($array as $subArray) { if (is_null($indexKey) && array_key_exists($columnKey, $subArray)) { $result[] = is_object($subArray)?$subArray->$columnKey: $subArray[$columnKey]; } elseif (array_key_exists($indexKey, $subArray)) { if (is_null($columnKey)) { $index = is_object($subArray)?$subArray->$indexKey: $subArray[$indexKey]; $result[$index] = $subArray; } elseif (array_key_exists($columnKey, $subArray)) { $index = is_object($subArray)?$subArray->$indexKey: $subArray[$indexKey]; $result[$index] = is_object($subArray)?$subArray->$columnKey: $subArray[$columnKey]; } } } return $result; } } ?>
array_column implementation that works on multidimensional arrays (not just 2-dimensional): <?php function array_column_recursive(array $haystack, $needle) { $found = []; array_walk_recursive($haystack, function($value, $key) use (&$found, $needle) { if ($key == $needle) $found[] = $value; }); return $found; } Taken from https://github.com/NinoSkopac/array_column_recursive
My version is closer to the original than http://github.com/ramsey/array_column <?php /** * Provides functionality for array_column() to projects using PHP earlier than * version 5.5. * @copyright (c) 2015 WinterSilence (http://github.com/WinterSilence) * @license MIT */ if (!function_exists('array_column')) { /** * Returns an array of values representing a single column from the input * array. * @param array $array A multi-dimensional array from which to pull a * column of values. * @param mixed $columnKey The column of values to return. This value may * be the integer key of the column you wish to retrieve, or it may be * the string key name for an associative array. It may also be NULL to * return complete arrays (useful together with index_key to reindex * the array). * @param mixed $indexKey The column to use as the index/keys for the * returned array. This value may be the integer key of the column, or * it may be the string key name. * @return array */ function array_column(array $array, $columnKey, $indexKey = null) { $result = array(); foreach ($array as $subArray) { if (!is_array($subArray)) { continue; } elseif (is_null($indexKey) && array_key_exists($columnKey, $subArray)) { $result[] = $subArray[$columnKey]; } elseif (array_key_exists($indexKey, $subArray)) { if (is_null($columnKey)) { $result[$subArray[$indexKey]] = $subArray; } elseif (array_key_exists($columnKey, $subArray)) { $result[$subArray[$indexKey]] = $subArray[$columnKey]; } } } return $result; } } ?>
array_column() will return duplicate values. Instead of having to use array_unique(), use the $index_key as a hack. **Caution: This may get messy when setting the $column_key and/or $index_key as integers.** <?php $records = [ [ 'id' => 2135, 'first_name' => 'John' ], [ 'id' => 3245, 'first_name' => 'Sally' ], [ 'id' => 5342, 'first_name' => 'Jane' ], [ 'id' => 5623, 'first_name' => 'Peter' ], [ 'id' => 6982, 'first_name' => 'Sally' ] ]; print_r(array_unique(array_column($records, 'first_name'))); // Force uniqueness by making the key the value. print_r(array_column($records, 'first_name', 'first_name')); print_r(array_column($records, 'id', 'first_name')); // Returns /* Array ( [0] => John [1] => Sally [2] => Jane [3] => Peter ) Array ( [John] => John [Sally] => Sally [Jane] => Jane [Peter] => Peter ) Array ( [John] => 2135 [Sally] => 6982 [Jane] => 5342 [Peter] => 5623 ) */ ?>
If you need to extract more than one column from an array, you can use array_intersect_key on each element, like so: function array_column_multi(array $input, array $column_keys) { $result = array(); $column_keys = array_flip($column_keys); foreach($input as $key => $el) { $result[$key] = array_intersect_key($el, $column_keys); } return $result; }
I added a little more functionality to the more popular answers here to support the $index_key parameter for PHP < 5.5 <?php // for php < 5.5 if (!function_exists('array_column')) { function array_column($input, $column_key, $index_key = null) { $arr = array_map(function($d) use ($column_key, $index_key) { if (!isset($d[$column_key])) { return null; } if ($index_key !== null) { return array($d[$index_key] => $d[$column_key]); } return $d[$column_key]; }, $input); if ($index_key !== null) { $tmp = array(); foreach ($arr as $ar) { $tmp[key($ar)] = current($ar); } $arr = $tmp; } return $arr; } } ?>
Here's a neat little snippet for filtering a set of records based on a the value of a column: <?php function dictionaryFilterList(array $source, array $data, string $column) : array { $new = array_column($data, $column); $keep = array_diff($new, $source); return array_intersect_key($data, $keep); } // Usage: $users = [ ['first_name' => 'Jed', 'last_name' => 'Lopez'], ['first_name' => 'Carlos', 'last_name' => 'Granados'], ['first_name' => 'Dirty', 'last_name' => 'Diana'], ['first_name' => 'John', 'last_name' => 'Williams'], ['first_name' => 'Betty', 'last_name' => 'Boop'], ['first_name' => 'Dan', 'last_name' => 'Daniels'], ['first_name' => 'Britt', 'last_name' => 'Anderson'], ['first_name' => 'Will', 'last_name' => 'Smith'], ['first_name' => 'Magic', 'last_name' => 'Johnson'], ]; var_dump(dictionaryFilterList(['Dirty', 'Dan'], $users, 'first_name')); // Outputs: [ ['first_name' => 'Jed', 'last_name' => 'Lopez'], ['first_name' => 'Carlos', 'last_name' => 'Granados'], ['first_name' => 'John', 'last_name' => 'Williams'], ['first_name' => 'Betty', 'last_name' => 'Boop'], ['first_name' => 'Britt', 'last_name' => 'Anderson'], ['first_name' => 'Will', 'last_name' => 'Smith'], ['first_name' => 'Magic', 'last_name' => 'Johnson'] ] ?>
//php < 5.5 if(function_exists('array_column')) { function array_column($arr_data, $col) { $result = array_map(function($arr){return $arr[$col]}, $arr_data); return $result; } }
if (!function_exists('array_column')) { function array_column($input, $column_key=null, $index_key=null) { $result = array(); $i = 0; foreach ($input as $v) { $k = $index_key === null || !isset($v[$index_key]) ? $i++ : $v[$index_key]; $result[$k] = $column_key === null ? $v : (isset($v[$column_key]) ? $v[$column_key] : null); } return $result; } }
Note that this function will return the last entry when possible keys are duplicated. <?php $array = array( array( '1-1', 'one', 'one', ), array( '1-2', 'two', 'one', ), ); var_dump(array_column($array, $value = 0, $index = 1)); var_dump(array_column($array, $value = 0, $index = 2)); // returns: /* array (size=2) 'one' => string '1-1' (length=3) 'two' => string '1-2' (length=3) array (size=1) 'one' => string '1-2' (length=3) */ ?>
Please note this function accepts 2D-arrays ONLY, and silently returns empty array when non-array argument is provided. Code: class testObject { public $a = 123; } $testArray = [new testObject(), new testObject(), new testObject()]; $result = array_column($testArray, 'a')); //array(0) { }
a simple solution: function arrayColumn(array $array, $column_key, $index_key=null){ if(function_exists('array_column ')){ return array_column($array, $column_key, $index_key); } $result = []; foreach($array as $arr){ if(!is_array($arr)) continue; if(is_null($column_key)){ $value = $arr; }else{ $value = $arr[$column_key]; } if(!is_null($index_key)){ $key = $arr[$index_key]; $result[$key] = $value; }else{ $result[] = $value; } } return $result; }
If array_column is not available you can use the following function, which also has the $index_key parameter: if (!function_exists('array_column')) { function array_column($array, $column_key, $index_key = null) { return array_reduce($array, function ($result, $item) use ($column_key, $index_key) { if (null === $index_key) { $result[] = $item[$column_key]; } else { $result[$item[$index_key]] = $item[$column_key]; } return $result; }, []); } }
Another option for older PHP versions (pre 5.5.0) is to use array_walk(): <?php $array = array( array('some' => 'var', 'foo' => 'bar'), array('some' => 'var', 'foo' => 'bar'), array('some' => 'var', 'foo' => 'bar') ); array_walk($array, function(&$value, $key, $return) { $value = $value[$return]; }, 'foo'); print_r($array); // Array // ( // [0] => bar // [1] => bar // [2] => bar // ) ?>
This didn't work for me recursively and needed to come up with a solution. Here's my solution to the function: if ( ! function_exists( 'array_column_recursive' ) ) { /** * Returns the values recursively from columns of the input array, identified by * the $columnKey. * * Optionally, you may provide an $indexKey to index the values in the returned * array by the values from the $indexKey column in the input array. * * @param array $input A multi-dimensional array (record set) from which to pull * a column of values. * @param mixed $columnKey The column of values to return. This value may be the * integer key of the column you wish to retrieve, or it * may be the string key name for an associative array. * @param mixed $indexKey (Optional.) The column to use as the index/keys for * the returned array. This value may be the integer key * of the column, or it may be the string key name. * * @return array */ function array_column_recursive( $input = NULL, $columnKey = NULL, $indexKey = NULL ) { // Using func_get_args() in order to check for proper number of // parameters and trigger errors exactly as the built-in array_column() // does in PHP 5.5. $argc = func_num_args(); $params = func_get_args(); if ( $argc < 2 ) { trigger_error( "array_column_recursive() expects at least 2 parameters, {$argc} given", E_USER_WARNING ); return NULL; } if ( ! is_array( $params[ 0 ] ) ) { // Because we call back to this function, check if call was made by self to // prevent debug/error output for recursiveness :) $callers = debug_backtrace(); if ( $callers[ 1 ][ 'function' ] != 'array_column_recursive' ){ trigger_error( 'array_column_recursive() expects parameter 1 to be array, ' . gettype( $params[ 0 ] ) . ' given', E_USER_WARNING ); } return NULL; } if ( ! is_int( $params[ 1 ] ) && ! is_float( $params[ 1 ] ) && ! is_string( $params[ 1 ] ) && $params[ 1 ] !== NULL && ! ( is_object( $params[ 1 ] ) && method_exists( $params[ 1 ], '__toString' ) ) ) { trigger_error( 'array_column_recursive(): The column key should be either a string or an integer', E_USER_WARNING ); return FALSE; } if ( isset( $params[ 2 ] ) && ! is_int( $params[ 2 ] ) && ! is_float( $params[ 2 ] ) && ! is_string( $params[ 2 ] ) && ! ( is_object( $params[ 2 ] ) && method_exists( $params[ 2 ], '__toString' ) ) ) { trigger_error( 'array_column_recursive(): The index key should be either a string or an integer', E_USER_WARNING ); return FALSE; } $paramsInput = $params[ 0 ]; $paramsColumnKey = ( $params[ 1 ] !== NULL ) ? (string) $params[ 1 ] : NULL; $paramsIndexKey = NULL; if ( isset( $params[ 2 ] ) ) { if ( is_float( $params[ 2 ] ) || is_int( $params[ 2 ] ) ) { $paramsIndexKey = (int) $params[ 2 ]; } else { $paramsIndexKey = (string) $params[ 2 ]; } } $resultArray = array(); foreach ( $paramsInput as $row ) { $key = $value = NULL; $keySet = $valueSet = FALSE; if ( $paramsIndexKey !== NULL && array_key_exists( $paramsIndexKey, $row ) ) { $keySet = TRUE; $key = (string) $row[ $paramsIndexKey ]; } if ( $paramsColumnKey === NULL ) { $valueSet = TRUE; $value = $row; } elseif ( is_array( $row ) && array_key_exists( $paramsColumnKey, $row ) ) { $valueSet = TRUE; $value = $row[ $paramsColumnKey ]; } $possibleValue = array_column_recursive( $row, $paramsColumnKey, $paramsIndexKey ); if ( $possibleValue ) { $resultArray = array_merge( $possibleValue, $resultArray ); } if ( $valueSet ) { if ( $keySet ) { $resultArray[ $key ] = $value; } else { $resultArray[ ] = $value; } } } return $resultArray; } }
Retrieve multiple columns from an array: $columns_wanted = array('foo','bar'); $array = array('foo'=>1,'bar'=>2,'foobar'=>3); $filtered_array = array_intersect_key(array_fill_keys($columns_wanted,'')); //filtered_array // array('foo'=>1,'bar'=>2);
Value for existing key in the resulting array is rewritten with new value if it exists in another source sub-array.
Presented function is good when You want to flatten nested array base on only one column, but if You want to flatten whole array You can use this method: /** * Method that transforms nested array into the flat one in below showed way: * [ * [ * [0]=>'today', * ], * [ * [0]=>'is', * [1]=>'very', * [2]=> [ * [0]=>'warm' * ], * ], * ] * * Into: * * ['today','is','very','warm'] * * @param $input * @return array */ private function transformNestedArrayToFlatArray($input) { $output_array = []; if (is_array($input)) { foreach ($input as $value) { if (is_array($value)) { $output_array = array_merge($output_array, $this->transformNestedArrayToFlatArray($value)); } else { array_push($output_array, $value); } } } else { array_push($output_array, $input); } return $output_array; }
<?php if (!function_exists('array_column')) { function array_column($input, $column_key, $index_key = NULL) { if (!is_array($input)) { trigger_error(__FUNCTION__ . '() expects parameter 1 to be array, ' . gettype($input) . ' given', E_USER_WARNING); return FALSE; } $ret = array(); foreach ($input as $k => $v) { $value = NULL; if ($column_key === NULL) { $value = $v; } else { $value = $v[$column_key]; } if ($index_key === NULL || !isset($v[$index_key])) { $ret[] = $value; } else { $ret[$v[$index_key]] = $value; } } return $ret; } } ?>