如果 array_column 不存在,以下解法可行。
if(!function_exists("array_column"))
{
function array_column($array,$column_name)
{
return array_map(function($element) use($column_name){return $element[$column_name];}, $array);
}
}
(PHP 5 >= 5.5.0, PHP 7, PHP 8)
array_column — 從輸入陣列中返回單一欄位的值
array_column() 會從 array
中,由 column_key
指定的單一欄位回傳其值。也可以選擇提供 index_key
,用輸入陣列中 index_key
欄位的值作為回傳陣列的索引鍵。
array
一個多維陣列或是一個物件陣列,用於提取其中一欄的值。如果是提供物件陣列,則可以直接提取公開屬性。若要提取受保護或私有屬性,則該類別必須同時實作 __get() 和 __isset() 魔術方法。
column_key
要回傳值的欄位。這個值可以是要擷取欄位的整數鍵,也可以是關聯陣列的字串鍵名或屬性名稱。它也可以是 null
來回傳完整的陣列或物件(這與 index_key
一起使用時,對於重新索引陣列很有用)。
index_key
要用作回傳陣列索引/鍵的欄位。這個值可以是欄位的整數鍵,也可以是字串鍵名。此值會像一般的陣列鍵一樣被轉型(然而,在 PHP 8.0.0 之前,也允許支援轉換為字串的物件)。
回傳一個陣列,表示輸入陣列中單一欄位的值。
範例 #1 從記錄集中取得名字的欄位
<?php
// 陣列表示可能從資料庫返回的記錄集
$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 )
範例 #2 從記錄集中獲取姓氏欄位,以 "id" 欄位作為索引
<?php
// 使用範例 #1 中的 $records 陣列
$last_names = array_column($records, 'last_name', 'id');
print_r($last_names);
?>
以上範例將輸出
Array ( [2135] => Doe [3245] => Smith [5342] => Jones [5623] => Doe )
範例 #3 從物件的公開 "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 )
範例 #4 從物件的私有 "name" 屬性中獲取名稱欄位,使用魔術方法 __get()。
<?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 )
如果 array_column 不存在,以下解法可行。
if(!function_exists("array_column"))
{
function array_column($array,$column_name)
{
return array_map(function($element) use($column_name){return $element[$column_name];}, $array);
}
}
如果您沒有 array_column(),也可以使用 array_map 函式。
範例
$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');
變成
array_map(function($element){return $element['last_name'];}, $a);
此函式不會保留陣列的原始鍵值(當未提供 index_key 時)。
您可以像這樣解決這個問題
<?php
// 取代
array_column($array, 'column');
// 以保留鍵值
array_combine(array_keys($array), array_column($array, 'column'));
?>
請注意,如果您使用 array_column 來重置索引,當索引值為 null 時,在不同的 PHP 版本中會有不同的結果,例如
<?php
$array = [
[
'name' =>'Bob',
'house' =>'big',
],
[
'name' =>'Alice',
'house' =>'small',
],
[
'name' =>'Jack',
'house' => null,
],
];
var_dump(array_column($array,null,'house'));
On 5.6.30, 7.0.0, 7.2.0 (not limited to) get the following results
array(3) {
["big"]=>
array(2) {
["name"]=>
string(3) "Bob"
["house"]=>
string(3) "big"
}
["small"]=>
array(2) {
["name"]=>
string(5) "Alice"
["house"]=>
string(5) "small"
}
[0]=>
array(2) {
["name"]=>
string(4) "Jack"
["house"]=>
NULL
}
}
The new index, null will be converted to int, and can be incremented according to the previous index, that is, if Alice "house" is also null, then Alice's new index is "0", Jack's new index is "1"
On 7.1.21, 7.2.18, 7.4.8 (not limited to) will get the following results
array(3) {
["Big"]=>
array(2) {
["name"]=>
string(3) "Bob"
["house"]=>
string(3) "Big"
}
["small"]=>
array(2) {
["name"]=>
string(5) "Alice"
["house"]=>
string(5) "small"
}
[""]=>
array(2) {
["name"]=>
string(4) "Jack"
["house"]=>
NULL
}
}
The new index null will be converted to an empty string
官方文件中未包含的一些說明。
1) array_column 不支援一維陣列,在這種情況下會返回一個空陣列。
2) $column_key 是從零開始的。
3) 如果 $column_key 超出有效索引範圍,則會返回一個空陣列。
陣列多個欄位
<?php
function array_columns() {
$args = func_get_args();
$array = array_shift($args);
if (!$args) {
return $array;
}
$keys = array_flip($args);
return array_map(function($element) use($keys) {
return array_intersect_key($element, $keys);
}, $array);
}
?>
範例
<?php
$products = [
[
'id' => 2,
'name' => 'Phone',
'price' => 210.3
],
[
'id' => 3,
'name' => 'Laptop',
'price' => 430.12
]
];
print_r(array_columns($products, 'name', 'price'));
?>
輸出
陣列
(
[0] => 陣列
(
[name] => Phone
[price] => 210.3
)
[1] => 陣列
(
[name] => Laptop
[price] => 430.12
)
)
可在多維陣列(不僅限於二維)上運作的 array_column 實作
<?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;
}
取自 https://github.com/NinoSkopac/array_column_recursive
因為我的 PHP 版本不支援這個函數,所以我根據自己的需求撰寫並稍微擴充了我的版本。
當你給定 $indexkey 值為 -1 時,它會保留關聯陣列的鍵值。
範例
$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'));
輸出
陣列
(
[0] => 10
[1] => 20
[2] => 30
)
print_r(array_column_ext($sample,'val1',-1));
輸出
陣列
(
['test1'] => 10
['test2'] => 20
['test3'] => 30
)
print_r(array_column_ext($sample,'val1','val2'));
輸出
陣列
(
[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;
}
?>
`array_column()` 的對應功能,也就是從多個欄位建立一個陣列,可以用 `array_map()` 來完成。
<?php
// 欄位
$lastnames = ['Skywalker', 'Organa', 'Kenobi'];
$firstnames = ['Luke', 'Leia', 'Obiwan'];
// 將欄位轉換為陣列
$characters = array_map(
fn ($l, $f) => ['lastname' => $l, 'firstname' => $f],
$lastnames, $firstnames
);
print_r($characters);
/*
[
0 => ['lastname' => 'Skywalker', 'firstname' => 'Luke']
1 => ['lastname' => 'Organa', 'firstname' => 'Leia']
2 => ['lastname' => 'Kenobi', 'firstname' => 'Obiwan']
]
*/
<?php
# 適用於 PHP < 5.5 版本
# 並且適用於 arrayObject 和物件陣列
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;
}
}
?>
這是一個用於根據欄位值篩選一組記錄的簡潔程式碼片段。
<?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 的 $index_key 參數。
<?php
// 適用於 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;
}
}
?>
請注意,當索引鍵重複時,此函式將會回傳最後一個項目。
<?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));
// 回傳值:
/*
array (size=2)
'one' => string '1-1' (length=3)
'two' => string '1-2' (length=3)
array (size=1)
'one' => string '1-2' (length=3)
*/
?>
//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;
}
}
我的版本比 http://github.com/ramsey/array_column 更接近原始版本
<?php
/**
* 為使用 PHP 5.5 以前版本的專案提供 array_column() 的功能。
* @copyright (c) 2015 WinterSilence (http://github.com/WinterSilence)
* @license MIT
*/
if (!function_exists('array_column')) {
/**
* 從輸入陣列返回表示單一欄位值的陣列。
* @param array $array 用於提取一欄位值的多維陣列。
* @param mixed $columnKey 要返回的值的欄位。此值可以是要擷取的欄位的整數鍵,也可以是關聯陣列的字串鍵名。它也可以是 NULL 以返回完整的陣列(與 index_key 一起使用以重新索引陣列)。
* @param mixed $indexKey 要用作返回陣列的索引/鍵的欄位。此值可以是欄位的整數鍵,也可以是字串鍵名。
* @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;
}
}
?>
如果您想要保留陣列鍵,並且希望它適用於物件屬性和陣列元素,並且希望它在陣列中的某些陣列/物件未定義給定鍵/屬性的情況下也能正常工作,基本上是最穩健的版本,而且速度夠快。
<?php
function array_column_keys(array|ArrayAccess $arr, string $col) {
// 類似 array_columns,但保留鍵值
//使其適用於物件和陣列
return array_map(fn($e) => (is_countable($e) ? ($e[$col]??null) : null) ?: (is_object($e) ? $e->$col : null), $arr);
}
?>
如果鍵值/屬性未定義,則結果陣列中的值將為 NULL。您可以根據需要使用 array_filter() 將這些值過濾掉。
<?php
class a {
public string $a = 'property a';
public string $b = 'property b';
}
$a1 = new a;
$a2 = new a;
$a2->a = 'plop';
$b = ['one'=> ['a'=>'plop'],
3 => $a1,
4 => $a2,
5 =>[],
'kud'=>new a];
return array_column_keys($b, 'a');
?>
回傳值
陣列
(
[one] => plop
[3] => property a
[4] => something else (應為 plop,原文有誤)
[5] =>
[kud] => property a
)
僅當索引鍵 (index_key) 的對應值在整個陣列中是唯一值時,索引鍵才適用。否則,只會選取陣列中具有相同索引鍵值的最後一個元素。
<?php
$records = array(
array(
'id' => 2135,
'first_name' => 'John',
'last_name' => 'Doe',
'company_id' => 1,
),
array(
'id' => 3245,
'first_name' => 'Sally',
'last_name' => 'Smith',
'company_id' => 1,
),
array(
'id' => 5342,
'first_name' => 'Jane',
'last_name' => 'Jones',
'company_id' => 1,
),
array(
'id' => 5623,
'first_name' => 'Peter',
'last_name' => 'Doe',
'company_id' => 2,
)
);
$first_names = array_column($records, 'first_name', 'company_id');
print_r($first_names);
?>
以上範例將輸出
<?php
Array
(
[1] => Jane
[2] => Peter
)
?>
若要將陣列中的值依相同的 `index_key` 分組,可以使用以下範例函式來取代 `array_column`。
<?php
function arrayed_column(array $array, int|string $column_key, int|string $index_key) {
$output = [];
foreach ($array as $item) {
$output[$item['index_key']][] = $item['column_key'];
}
return $output;
}
$first_names = arrayed_column($records, 'first_name', 'company_id');
print_r($first_names);
?>
輸出結果:
<?php
陣列
(
[1] => 陣列
(
[0] => John
[1] => Sally
[2] => Jane
)
[2] => 陣列
(
[0] =>Peter
)
)
?>
如果來源陣列中的項目沒有 column_key 元素,則 array_column 會靜默地跳過該項目,並返回比來源陣列短的陣列。
如果項目無法透過 index_key 唯一識別,則無法判斷哪些項目被跳過,因為沒有 index_key 的 array_column 會返回一個普通的列表。
<?php
$array = [
['a' => '0th', 'b' => 'zero'],
['a' => '1st', 'b' => 'one'],
['a' => '2nd' /* 哎呀 */],
['a' => '3rd', 'b'=>'three']];
var_export(array_column($array, 'b'));
var_export(array_column($array, 'b', 'a'));
?>
以下函式可能有助於從索引陣列的所有值建立欄位
<?php
函式 array_column_all(陣列 $arrays): 陣列
{
$output = [];
$columnCount = count($arrays[0]);
for ($i = 0; $i < $columnCount; $i++)
{
$output [] = array_column($arrays, $i);
}
return $output;
}
?>
用法
-----
<?php
array_column_all(
[
['A1', 'A2', 'A3'],
['B1', 'B2', 'B3'],
['C1', 'C2', 'C3'],
]
);
?>
這會輸出
-------------------
陣列
(
[0] => 陣列
(
[0] => A1
[1] => B1
[2] => C1
)
[1] => 陣列
(
[0] => A2
[1] => B2
[2] => C2
)
[2] => 陣列 (Array)
(
[0] => A3
[1] => B3
[2] => C3
)
)
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;
}
}
一個簡單的解決方案
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;
}
如果您需要從陣列中提取多個欄位,您可以對每個元素使用 array_intersect_key,如下所示
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;
}
array_column() 會返回重複的值。
與其使用 array_unique(),不如使用 $index_key 作為一個小技巧。
**注意:當將 $column_key 和/或 $index_key 設定為整數時,這可能會變得混亂。**
<?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')));
// 強制唯一性,將值設為鍵名。
print_r(array_column($records, 'first_name', 'first_name'));
print_r(array_column($records, 'id', 'first_name'));
// 回傳
/*
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
)
*/
?>
如果 `array_column` 無法使用,您可以使用以下函式,它也有 `$index_key` 參數
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;
}, []);
}
}
如果您想重新排列一個具有兩層的陣列(可能來自資料庫請求),請改用 `array_walk`
<?php
$yamlList= [
['title'=>'hallo ich','identifier'=>'ich','Klaus'=>'doof',],
['title'=>'hallo du','identifier'=>'du','Klaus'=>'doof',],
['title'=>'hallo er','identifier'=>'er','Klaus'=>'doof',],
];
echo ('輸入'."\n".print_r($yamlList,true)."\n");
array_walk($yamlList, function (&$value,$key) {
$value= [
$value['title'],
$value['identifier'],
];
});
echo ("\n".'輸出'."\n".print_r($yamlList,true)."\n");
?>
結果
===========
...
輸出
陣列
(
[0] => 陣列
(
[0] => hallo ich
[1] => ich
)
[1] => 陣列
(
[0] => hallo du
[1] => du
)
[2] => 陣列 (Array)
(
[0] => hallo er
[1] => er
)
)