Reputation: 70819
I have an array of arrays, with the following structure :
array(array('page' => 'page1', 'name' => 'pagename1')
array('page' => 'page2', 'name' => 'pagename2')
array('page' => 'page3', 'name' => 'pagename3'))
Is there a built-in function that will return a new array with just the values of the 'name' keys? so I'd get:
array('pagename1', 'pagename2', 'pagename3')
Upvotes: 28
Views: 40830
Reputation: 47874
Consider this sample input array to expose nuanced differences in script behaviors:
$array = [
'a' => ['page' => 'page1', 'name' => 'pagename1'],
'b' => ['page' => 'page2', 'name' => 'pagename2'],
'c' => ['page' => 'page3', 'name' => 'pagename3'],
'd' => ['page' => 'page4',],
];
Populate a new indexed array from column values with array_column()
: (Demo)
var_export(array_column($array, 'name'));
# array (
# 0 => 'pagename1',
# 1 => 'pagename2',
# 2 => 'pagename3',
# )
Missing column values are no problem.
Populate a new array preserving first level keys with array_map()
: (Demo)
var_export(array_map(fn($row) => $row['name'] ?? 'missing', $array));
# array (
# 'a' => 'pagename1',
# 'b' => 'pagename2',
# 'c' => 'pagename3',
# 'd' => 'missing',
# )
Missing column values must be explicitly handled to avoid an error.
Populate a new indexed array from column values with array_reduce()
: (Demo)
var_export(array_reduce($array, fn($result, $row) => array_merge($result, [$row['name'] ?? 'missing']), []));
# array (
# 0 => 'pagename1',
# 1 => 'pagename2',
# 2 => 'pagename3',
# 3 => 'missing',
# )
Missing column values must be explicitly handled to avoid an error.
Overwrite the rows of the original array with the column values with array_walk()
: (Demo)
array_walk($array, fn(&$row) => $row = $row['name'] ?? 'missing');
var_export($array);
# array (
# 'a' => 'pagename1',
# 'b' => 'pagename2',
# 'c' => 'pagename3',
# 'd' => 'missing',
# )
Missing column values must be explicitly handled to avoid an error.
If all rows contain the sought column value, then a body-less loop can be used with array destructuring to avoid declaring a temporary variable: (Demo)
$result = [];
foreach ($array as ['name' => $result[]]);
var_export($result);
Note that you cannot declare the first level key as a variable and use it as the key in the result array with this approach because values are assigned BEFORE keys are assigned.
If you need to handle potentially missing columns, then a classic loop with a null coalesced default value is suitable. (Demo)
$result = [];
foreach ($array as $row) {
$result[] = $row['name'] ?? 'missing';
}
var_export($result);
If you want to merely mutate the original input array instead of generating a new array, then use a foreach loop and modify the rows by reference. (Demo)
foreach ($array as &$row) {
$row = $row['name'] ?? 'missing';
}
var_export($array);
Certainly recursion is overkill for this simple task, but for completeness, array_walk_recursive()
can be used to access "leaf nodes" in the structure and collect qualifying values in the $result
array by reference. (Demo)
$colName = 'name';
$result = [];
array_walk_recursive(
$array,
function ($v, $k) use ($colName, &$result) {
if ($k === $colName) {
$result[] = $v;
}
}
);
var_export($result);
Upvotes: 0
Reputation: 1952
You can get column, bind key value as well:
$a = array(
array(
'id' => 5698,
'first_name' => 'Peter',
'last_name' => 'Griffin',
),
array(
'id' => 4767,
'first_name' => 'Ben',
'last_name' => 'Smith',
),
array(
'id' => 3809,
'first_name' => 'Joe',
'last_name' => 'Doe',
)
);
if you want only column then use:
$last_names = array_column($a, 'last_name');
print_r($last_names);
if you want to bind key and values then use:
$last_names = array_column($a, 'last_name', 'id');
print_r($last_names);
Upvotes: 0
Reputation: 219804
As of PHP 5.5
you can use array_column()
:
<?php
$samples=array(
array('page' => 'page1', 'name' => 'pagename1'),
array('page' => 'page2', 'name' => 'pagename2'),
array('page' => 'page3', 'name' => 'pagename3')
);
$names = array_column($samples, 'name');
print_r($names);
Upvotes: 83
Reputation: 11583
Why does it have to be a built in function? No, there is none, write your own.
Here is a nice and easy one, as opposed to others in this thread.
$namearray = array();
foreach ($array as $item) {
$namearray[] = $item['name'];
}
In some cases where the keys aren't named you could instead do something like this
$namearray = array();
foreach ($array as $key => $value) {
$namearray [] = $value;
}
Upvotes: 19
Reputation: 134
With array_reduce:
$names = array_reduce($array, function ($carry, $item) {
return array_merge($carry, [$item['name']]);
}, []);
Upvotes: 0
Reputation: 7485
Not a 'built-in', but short arrow functions make for abrreviated explicit coding (introduced in Php v7.4.) and can be used with array_map for array transformations.
Here applying a callback to each member of the array that returns the desired attribute from each subarray:
<?php
$data =
[
['page' => 'page1', 'name' => 'pagename1'],
['page' => 'page2', 'name' => 'pagename2'],
['page' => 'page3', 'name' => 'pagename3']
];
$names = array_map(fn($v) => $v['name'], $data);
var_export($names);
Output:
array (
0 => 'pagename1',
1 => 'pagename2',
2 => 'pagename3',
)
The OP posted this question before array_column
exisited (from Php 5.5.0). This answers the original question with a short solution:
$names = array_column($data, 'name');
But a simple loop is also trite:
foreach($data as $item) $names[] = $item['name'];
Upvotes: 0
Reputation: 499
Just to extend on some of the answers here, as of PHP 5.5, array_column is what you want.
It actually has a few possible uses.
Using the sample array below, here are the different ways to use array_column.
$a = array(
array('id' => '1', 'name' => 'Joe'),
array('id' => '2', 'name' => 'Jane')
);
Retrieving a single column as the array
$b = array_column($a, 'name');
Would give you. Notice the auto keys starting from 0, as per a normal array.
$b[0] = 'Joe';
$b[1] = 'Jane';
Retrieving the full array with a column as the index.
$c = array_column($a, NULL, 'id');
Would result in the following.
$c[1] = array('id' => '1', 'name' => 'Joe');
$c[2] = array('id' => '2', 'name' => 'Jane');
Notice how the column I selected as the third parameter becomes the key for each item and I get the full array by setting the second parameter to null.
Of course, the final usage is to set both the 2nd and 3rd params.
$d = array_column($a, 'name', 'id');
Would give you the following.
$d[1] = 'Joe';
$d[2] = 'Jane';
I personally use the full 3 params for creating select option lists. If I have a table with my options, I query the table and get the result and pass it into this to get a list with the key as the value and the label. This is a brilliant way for building info sets that need to intersect by the index as well.
Upvotes: -1
Reputation: 75
Yes, there is a php built-in function called array_column which does what you are looking for.
You would call it something like $name_keys = array_column($array, 'name');
to get the result that you are looking for.
Please refer to the following entry in the PHP manual for more details:
http://php.net/manual/en/function.array-column.php
Upvotes: 1
Reputation: 1281
Well there is. At least for PHP > 5.5.0 and it is called array_column
The PHP function takes an optional $index_key
parameter that - as per the PHP website - states:
$index_key
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
In the answers here, i see a stripped version without the optional parameter. I needed it, so, here is the complete function:
if (!function_exists('array_column')) {
function array_column($array, $column, $index_key = null) {
$toret = array();
foreach ($array as $key => $value) {
if ($index_key === null){
$toret[] = $value[$column];
}else{
$toret[$value[$index_key]] = $value[$column];
}
}
return $toret;
}
}
Upvotes: 6
Reputation: 37
if (!function_exists('array_column')) {
function array_column($array,$column) {
$col = array();
foreach ($array as $k => $v) {
$col[]=$v[$column];
}
return $col;
}
}
This should work for php versions < 5.5 and degrade in case the function exist
Upvotes: 1
Reputation: 3526
I don't think there is any need to have a built in function for this. There may be an array in your those array.
$samples=array(
array('page' => 'page1', 'name' => 'pagename1'),
array('page' => 'page2', 'name' => 'pagename2'),
array('page' => 'page3', 'name' => 'pagename3')
);
$output1=array();
$output2=array();
foreach($samples as $sample){
array_push($output1,$sample['name']);
$output2[]=array_splice($sample,1);
}
print_r($output1);
print_r($output2);
in $output1 is the output what you want if you want only to remove the 'page' indexing' part then $output2.
if you need all the values from the that array and indexes numerically the array then you can use
$array_1=array_values($samples);
but what i understand, you didn't want this.
Upvotes: 0
Reputation: 96159
You can extend the ArrayIterator class and override the method mixed current(void)
.
class Foo extends ArrayIterator {
protected $index;
public function __construct($array, $index) {
parent::__construct($array);
$this->index = $index;
}
public function current() {
$c = parent::current();
return isset($c[$this->index]) ? $c[$this->index] : null;
}
}
$a = array(
array('page' => 'page1', 'name' => 'pagename1'),
array('name' => '---'),
array('page' => 'page2', 'name' => 'pagename2'),
array('page' => 'page3', 'name' => 'pagename3')
);
$f = new Foo($a, 'page');
foreach($f as $e) {
echo $e, "\n";
}
prints
page1
page2
page3
Upvotes: 0
Reputation: 19441
Similar to fuentesjrs solution, but a bit more generic using array_walk() with a custom callback:
// Define the callback
function extract_named_sub_elements(&$item, $key, $name) {
$item = $item[$name];
}
// Test data
$original = array(
array('page' => 'page1', 'name' => 'pagename1'),
array('page' => 'page2', 'name' => 'pagename2'),
array('page' => 'page3', 'name' => 'pagename3'),
);
// Use a copy, as array_walk() operates directly on the passed in array
$copy = $original;
// Substitute 'name' with whatever element you want to extract, e.g. 'page'
array_walk($copy, 'extract_named_sub_elements', 'name');
print_r($copy);
Upvotes: 1
Reputation: 52318
Here's a functional way of doing it:
$data = array(
array('page' => 'page1', 'name' => 'pagename1'),
array('page' => 'page2', 'name' => 'pagename2'),
array('page' => 'page3', 'name' => 'pagename3'));
$result = array_map(create_function('$arr', 'return $arr["name"];'), $data);
print_r($result);
Upvotes: 14