I want to generate a list of the second level of keys used. Each record does not contain all of the same keys. But I need to know what all of the keys are. array_keys() doesn't work, it only returns a list of numbers.
Essentially the output Im looking for is:
action, id, validate, Base, Ebase, Ftype, Qty, Type, Label, Unit
I have a large multi-dimensional array that follows the format:
Array
(
[0] => Array
(
[action] => A
[id] => 1
[validate] => yes
[Base] => Array
(
[id] => 2945
)
[EBase] => Array
(
[id] => 398
)
[Qty] => 1
[Type] => Array
(
[id] => 12027
)
[Label] => asfhjaflksdkfhalsdfasdfasdf
[Unit] => asdfas
)
[1] => Array
(
[action] => A
[id] => 2
[validate] => yes
[Base] => Array
(
[id] => 1986
)
[FType] => Array
(
[id] => 6
)
[Qty] => 1
[Type] => Array
(
[id] => 13835
)
[Label] => asdssdasasdf
[Unit] => asdger
)
)
Thanks for the help!
<?php
// Gets a list of all the 2nd-level keys in the array
function getL2Keys($array)
{
$result = array();
foreach($array as $sub) {
$result = array_merge($result, $sub);
}
return array_keys($result);
}
?>
edit: removed superfluous array_reverse() function
array_keys(call_user_func_array('array_merge', $a));
Merge all values and retrieve the resulting keys.
One liner:
$keys=array_unique(array_reduce(array_map('array_keys',$data),'array_merge',[]));
Or in a function:
function get_array_children_keys($data) {
return array_unique(
array_reduce(array_map('array_keys', $data), 'array_merge', [])
);
}
Now lets break this down with an example, here is some sample data:
[
['key1' => 0],
['key1' => 0, 'key2' => 0],
['key3' => 0]
]
Starting with the inner most function, we run array_map with the array_keys function:
array_map('array_keys', $data)
This gives us the keys of from all child arrays
[
['key1'],
['key1', 'key2'],
['key3']
]
Then we run the array_reduce on the data with the array_merge callback and an empty array as the initial value:
array_reduce(..., 'array_merge', []);
This converts our multiple arrays into 1 flat array:
[
'key1',
'key1',
'key2',
'key3'
]
Now we strip out our duplicates with array_unique:
array_unique(...)
And end up with all our keys:
[
'key1',
'key2',
'key3'
]
foreach($bigArray as $array){
foreach($array as $key=>$value){
echo $key;
}
}
That should do what you want.
What about something like this :
$your_keys = array_keys($your_array[0]);
Of course, this is considering all sub-arrays have the same keys ; in this case, you only need the keys of the first sub-array (no need to iterate over all first-level sub-arrays, I guess)
And, as a shortened / simplified example :
$your_array = array(
array(
'action' => 'A',
'id' => 1,
'base' => array('id' => 145),
),
array(
'action' => 'B',
'id' => 2,
'base' => array('id' => 145),
),
array(
'action' => 'C',
'id' => 3,
'base' => array('id' => 145),
)
);
$your_keys = array_keys($your_array[0]);
var_dump($your_keys);
Will get you :
array
0 => string 'action' (length=6)
1 => string 'id' (length=2)
2 => string 'base' (length=4)
You can the use implode to get the string you asked for :
echo implode(', ', $your_keys);
will get you :
action, id, base
ie, the list of the keys of the first sub-array.
function __getAll2Keys($array_val){
$result = array();
$firstKeys = array_keys($array_val);
for($i=0;$i<count($firstKeys);$i++){
$key = $firstKeys[$i];
$result = array_merge($result,array_keys($array_val[$key]));
}
return $result;
}
try this function. It will return as you want.
While #raise answers provides a shortcut, it fails with numeric keys. The following should resolve this:
$secondKeys=array_unique(call_user_func_array('array_merge', array_map('array_keys',$a)));
array_map('array_keys',$a) : Loop through while getting the keys
...'array_merge'... : Merge the keys array
array_unique(... : (optional) Get unique keys.
I hope it helps someone.
UPDATE:
Alternatively you can use
$secondKeys=array_unique(array_merge(...array_map('array_keys', $a)));
That provides same answer as above, and much faster.
My proposal, similar to this answer but faster and using spread operator (PHP 5.6+).
array_merge(...array_values($fields))
if you want move names to array values and reset keys to 0..n just use array_keys in last step.
array_keys(array_merge(...array_values($fields)))
Maybe you can use array_map function, which allows you to avoid array iteration and return an array with the keys you need as values.
will be like this
$newArray = array_map(function($value){return array_keys($value);},$yourArray);
var_dump($newArray);
array (size=2)
0 =>
array (size=9)
0 => string 'action' (length=6)
1 => string 'id' (length=2)
2 => string 'validate' (length=8)
3 => string 'Base' (length=4)
4 => string 'EBase' (length=5)
5 => string 'Qty' (length=3)
6 => string 'Type' (length=4)
7 => string 'Label' (length=5)
8 => string 'Unit' (length=4)
1 =>
array (size=9)
0 => string 'action' (length=6)
1 => string 'id' (length=2)
2 => string 'validate' (length=8)
3 => string 'Base' (length=4)
4 => string 'FType' (length=5)
5 => string 'Qty' (length=3)
6 => string 'Type' (length=4)
7 => string 'Label' (length=5)
8 => string 'Unit' (length=4)
With this function you can get all keys from a multidimensional array
function arrayKeys($array, &$keys = array()) {
foreach ($array as $key => $value) {
$keys[] = $key;
if (is_array($value)) {
$this->arrayKeys($value, $keys);
}
}
return $keys;
}
Only if all records have the same keys you could do:
$firstItem = reset($array);
$keys = array_keys($firstItem);
Obviously, this is not the correct answer to this specific question, where the records have different keys. But this might be the question you find when looking how to retrieve second level keys from an array where all keys are the same (I did). If all the record have the same keys, you can simply use the first item in the array with reset() and get the keys from the first item with array_keys().
Related
I am trying to merge two array with the same key into one.
After i dump these variables
var_dump($allArtistsName);
var_dump($allTracksName);
I get this output
First array
array (size=3749)
0 => string 'Avicii' (length=6)
1 => string 'Arctic Monkeys' (length=14)
2 => string 'DJ Antoine' (length=10)
and second array
array (size=2135)
0 => string 'Hey Brother' (length=11)
1 => string 'Do I Wanna Know?' (length=16)
2 => string 'House Party - Airplay Edit' (length=26)
Basicly key 0 from first array matches with key 0 from second array.
So i am tryin go merge them somehow.
I have tried aarray_merge and array_merge_recursive
but i does not seem to work.
How i can solve this the best ?
EDIT:
My expected output would be something like
[
0 => [
'track' => 'Hey Brother',
'artists' => Avicii
1 => [
'track' => 'x',
'artists' => y
]
Several options:
$a = ['Avicii', 'Arctic Monkeys', 'DJ Antoine'];
$t = ['Hey Brother', 'Do I Wanna Know?', 'House Party - Airplay Edit'];
// option 1 - artist name as key, track as value
print_r(array_combine($a, $t));
// option 2 - artist name and track as subarray
print_r(array_map(null, $a, $t));
// option 3 - your expected output
$newArray = [];
foreach ($a as $key => $v) {
$newArray[] = [
'artist' => $v,
'track' => $t[$key],
];
}
You can use array_map thingie with a callback:
<?php
$artists = [
'Avicii',
'Arctic Monkeys',
'DJ Antoine',
];
$tracks = [
'Hey Brother',
'Do I Wanna Know?',
'House Party - Airplay Edit',
];
$merged = array_map(
function ($artist, $track) {
return ['artist' => $artist, 'track' => $track];
},
$artists,
$tracks
);
print_r($merged);
Output will be:
Array
(
[0] => Array
(
[artist] => Avicii
[track] => Hey Brother
)
[1] => Array
(
[artist] => Arctic Monkeys
[track] => Do I Wanna Know?
)
[2] => Array
(
[artist] => DJ Antoine
[track] => House Party - Airplay Edit
)
)
I have encountered an array of serialized values like below:
Array
(
[primary] => Array
(
[key_type_0_key_name] => a:1:{i:0;s:5:"27232";}
[key_type_1_key_name] => a:1:{i:0;s:5:"27231";}
[key_type_2_key_name] => a:1:{i:0;s:5:"27147";}
[key_type_3_key_name] => a:1:{i:0;s:5:"27157";}
)
[additional] => Array
(
[key_type_0_key_othername] => a:1:{i:0;s:5:"27169";}
[key_type_1_key_othername] => a:1:{i:0;s:5:"27160";}
[key_type_2_key_othername] => a:1:{i:0;s:5:"27103";}
[key_type_3_key_othername] => a:1:{i:0;s:5:"27149";}
)
)
Now I need to apply two functions namely, unserialize and array_shift in specified order to extract the scalar values like 27169 and store in another array, how can I do that in one pass of array_map or I have to run array_map two times compulsorily ?
Also one problem is with recursion, only array_walk_recursive handles recursion properly, but in my case if I try below code, I am getting the given error:
return array_walk_recursive($array, function ( &$value ) {
$value = array_shift( unserialize( $value ) );
});
Error:
Strict Standards: Only variables should be passed by reference in /path/to/file.php on line 367
Expected Result:
Array
(
[primary] => Array
(
27232
27231
27147
27157
)
[additional] => Array
(
27169
27160
27103
27149
)
)
With no calls to array_map.
<?php
$data = [
'primary' =>
[
'a:1:{i:0;s:5:"27232";}',
'a:1:{i:0;s:5:"27231";}',
'a:1:{i:0;s:5:"27147";}',
'a:1:{i:0;s:5:"27157";}'
],
'additional' =>
[
'a:1:{i:0;s:5:"27169";}',
'a:1:{i:0;s:5:"27160";}',
'a:1:{i:0;s:5:"27103";}',
'a:1:{i:0;s:5:"27149";}'
]
];
$numbers = [];
foreach($data as $key=>$value) {
foreach($value as $k=>$v) {
$unserialized = unserialize($v);
$numbers[$key][] = (int) array_shift($unserialized);
}
}
var_dump($numbers);
Output:
array (size=2)
'primary' =>
array (size=4)
0 => int 27232
1 => int 27231
2 => int 27147
3 => int 27157
'additional' =>
array (size=4)
0 => int 27169
1 => int 27160
2 => int 27103
3 => int 27149
Here a mutating array_walk example with three array_map calls. Far uglier and harder to read in my eyes, but each their own:
array_walk($data, function(&$v) {
$v = array_map('intval', array_map('array_shift', array_map('unserialize', $v)));
}
);
var_dump($data);
Output:
array (size=2)
'primary' =>
array (size=4)
0 => int 27232
1 => int 27231
2 => int 27147
3 => int 27157
'additional' =>
array (size=4)
0 => int 27169
1 => int 27160
2 => int 27103
3 => int 27149
Allow me to answer the question that was asked. Yes, yes you can... and you nearly had it!
You only needed to change the way that you were accessing the value. Replace the array_shift() call with [0] -- this eliminates the Strict Standards error.
Code: (Demo)
$array=[
'primary' =>
[
'a:1:{i:0;s:5:"27232";}',
'a:1:{i:0;s:5:"27231";}',
'a:1:{i:0;s:5:"27147";}',
'a:1:{i:0;s:5:"27157";}'
],
'additional' =>
[
'a:1:{i:0;s:5:"27169";}',
'a:1:{i:0;s:5:"27160";}',
'a:1:{i:0;s:5:"27103";}',
'a:1:{i:0;s:5:"27149";}'
]
];
array_walk_recursive($array,function(&$v){$v=unserialize($v)[0];});
var_export($array);
Output:
array (
'primary' =>
array (
0 => '27232',
1 => '27231',
2 => '27147',
3 => '27157',
),
'additional' =>
array (
0 => '27169',
1 => '27160',
2 => '27103',
3 => '27149',
),
)
I've got an array that looks like this:
'coilovers' =>
'strut_and_individual_components' =>
'complete_strut' =>
0 =>
array (size=5)
'achse' => string 'Oś tylnia' (length=10)
'position' => string 'Prawo' (length=5)
'material' => string 'Stal' (length=4)
'variante' => string 'Wariant 3' (length=9)
'img' => string 'gewindefahrwerk_federbein_komplett_level3.png'
'hls_components' =>
'assembly_pump_unit' =>
0 =>
'achse' => string 'Assembly pump unit' (length=18)
'img' => string 'hls_komponenten_baugruppe_pumpeneinheit_level3.png'
Now I'm getting string parameter that looki for example like : [coilovers][strut_and_individual_components][complete_strut][0]
And now I want to to unset whole branch of that array based on that parameter. So far I've accomplished how to read value but that parameter and it looks like.
private function str_index_array(&$arr, $indexes) {
$arr_indexes = explode('][',trim($indexes,'[]'));
$session_array = &$arr;
foreach($arr_indexes as $index) {
$session_array = &$session_array[$index];
}
}
But I'm stuck now, I need to check if that element is last element in array and in previous element is that previous element is empty if its empty unset whole brunch. Any ideas?
I'm sure some PHP/array/reference expert can come up with better ways of doing this, but here is one bug-ugly solution. I've set up a loop to obtain a reference to the last but second level index, and test and delete the sub-indexes from there. Note that there is no error-checking to test if the indexes actually exist before using them.
<?php
$a = array (
'coilovers' => array (
'strut_and_individual_components' => array (
'complete_strut' => array (
0 => array (
'achse' => 'Os tylnia',
'position' => 'Prawo',
'material' => 'Stal',
'variante' => 'Wariant 3',
'img' => 'gewindefahrwerk_federbein_komplett_level3.png'
)
)
)
),
'hls_components' => array (
'assembly_pump_unit' => array (
0 => array (
'achse' => 'Assembly pump unit',
'img' => 'hls_komponenten_baugruppe_pumpeneinheit_level3.png'
)
)
)
);
function delete_index (&$arr, $indexes) {
$arr_indexes = explode('][',trim($indexes,'[]'));
for ($i = 0; $i < count($arr_indexes) - 2; $i++) {
$arr = &$arr[$arr_indexes[$i]];
}
$ix1 = $arr_indexes[$i];
$ix2 = $arr_indexes[$i+1];
unset ($arr[$ix1][$ix2]);
if (empty ($arr[$ix1]))
unset ($arr[$ix1]);
}
print_r ($a);
delete_index ($a, '[coilovers][strut_and_individual_components][complete_strut][0]');
print_r ($a);
HI,
I got two array.
var_dump($tbDateArr);
var_dump($tbTitleArr);
output:
array
0 =>
object(stdClass)[16]
public 'eventDate' => string '5' (length=1)
1 =>
object(stdClass)[17]
public 'eventDate' => string '16' (length=2)
array
0 =>
object(stdClass)[18]
public 'eventTitle' => string 'mar' (length=10)
1 =>
object(stdClass)[19]
public 'eventTitle' => string 'tri' (length=10)
BTW,I print them as this,
print_r($tbDateArr);
echo '<br>';
print_r($tbTitleArr);
Array ( [0] => stdClass Object ( [eventDate] => 5 ) [1] => stdClass Object ( [eventDate] => 16 ) )
Array ( [0] => stdClass Object ( [eventTitle] => mar ) [1] => stdClass Object ( [eventTitle] => tri ) )
I tried to combin them,
$dataArr = array_combine($tbDateArr, $tbTitleArr);
I JUST WANT THE SIMPLY RESULT as this,
Array
(
[5] => mar
[16] => tri
)
Is there anything wrong? Appreciated for your help.
[updated with array_merge]
array
0 =>
object(stdClass)[16]
public 'eventDate' => string '5' (length=1)
1 =>
object(stdClass)[17]
public 'eventDate' => string '16' (length=2)
2 =>
object(stdClass)[18]
public 'eventTitle' => string 'fuzhou mar' (length=10)
3 =>
object(stdClass)[19]
public 'eventTitle' => string 'weihai tri' (length=10)
Assuming that $tbDateArr and $tbTitleArr entries only have a single property (eventDate and eventTitle respectively), you can do this:
$array = array_combine(
array_map('current', $tbDateArr),
array_map('current', $tbTitleArr)
);
If they have (or can have) more than a single property, you're better off using a good old foreach, assuming they have matching keys (if they don't, just array_values them beforehand):
$array = array();
foreach ($tbDateArr as $key => $value) {
$array[$value] = $tbTableArr[$key];
}
You can't directly combine the arrays, since the values you need are stored as properties in objects -- you have to pull these values out and use them:
$keys = array_map('getEventDate', $tbDateArr);
$values = array_map('getEventDate', $tbTitleArr);
print_r(array_combine($keys, $values));
function getEventDate($o) {
return $o->eventDate;
}
EDIT
this works
$arr1 = array(
"5",
"16",
);
$arr2 = array(
"mar",
"tri",
);
$result = array_combine($arr1, $arr2);
print_r($result);
You are trying to combine arrays which containing objects. array_combine using its first argument for keys second argument as values.
i have foreach, which generate following arrays:
==== array 1 ====
array
0 =>
array
'tag' => string 'daf' (length=3)
1 =>
array
'tag' => string 'daa' (length=3)
2 =>
array
'tag' => string 'daf' (length=3)
3 =>
array
'tag' => string 'daaa' (length=4)
4 =>
array
'tag' => string 'daf' (length=3)
5 =>
array
'tag' => string 'daa' (length=3)
6 =>
array
'tag' => string 'daf' (length=3)
7 =>
array
'tag' => string 'daf' (length=3)
8 =>
array
'tag' => string 'daf' (length=3)
9 =>
array
'tag' => string 'abd' (length=3)
10 =>
array
'tag' => string 'abdaa' (length=5)
11 =>
array
'tag' => string 'abda' (length=4)
==== array 2 ====
array
0 =>
array
'tag' => string 'daf' (length=3)
1 =>
array
'tag' => string 'test1' (length=5)
As output i want to get something like:
array
'daf' => '7'
'daa' => '2'
'daaa' => '1'
'abd' => '1'
'abdaa' => '1'
'abda' => '1'
'test1' => '1'
The value of the new array is the count of the element from all aray generatet from the loop. array_count_values() doesn't work here...any suggestions, how to solve the problem?
Did not notice it was 2 dimensional array.
Here is another code.
var_export(
array_count_values(
call_user_func_array('array_merge', array_merge($array1, $array2))
)
);
Something a bit like this should work:
$result = array();
foreach (array_merge($array1, $array2) as $item) {
$name = $item['tag'];
if (!isset($result[$name])) {
$result[$name] = 0;
}
$result[$name]++;
}
Let's make some use of the Standard PHP Library (SPL).
You can "flatten" an array with an RecursiveArrayIterator and RecursiveIteratorIterator. As a result you get an iterator that visits each leaf of your n-dimensional array and still let's you access the actual key of the element. In the next step concat both RecursiveIteratorIterators with an AppendIterator acting like a single interator that visits each element in all of its inner (appended) iterators.
$ai = new AppendIterator;
$ai->append(new RecursiveIteratorIterator(new RecursiveArrayIterator($array1)));
$ai->append(new RecursiveIteratorIterator(new RecursiveArrayIterator($array2)));
$counters = array();
foreach($ai as $key=>$value) {
if ( 'tag'===$key ) {
// # because I don't care whether this array element exists beforehand or not.
// $value has to be something that can be used as an array key (strings in this case)
#$counters[$value] += 1;
}
}
If you want you can even use a FilterIterator instead of the if('tag'===$key). But imho this doesn't increase the readability/value of the code ;-)