Extract inner array from a PHP associative array using some external keys - php

I have a array $a and some key arrays e.g. $keys1, $keys2,....
$a = array('a'=>array('b'=>array('c'=>array('d'=>123,'s'=>4),'r'=>3),'q'=>2),'p'=>1);
$keys1 = array('a','b','c');
$keys2 = array('a','b');
$a = Array
(
[a] => Array
(
[b] => Array
(
[c] => Array
(
[d] => 123
[s] => 4
)
[r] => 3
)
[q] => 2
)
[p] => 1
)
whenever $keys1 is used, output should be
Array
(
[d] => 123
[s] => 4
)
or whenever $keys2 is used, output should be
Array
(
[c] => Array
(
[d] => 123
[s] => 4
)
)
this is very simple I can achieve result by using $a[a][b][c] in first case and by using $a[a][b] in second case
Problem: these $keys are provided in form of array at run time,
Is there any function in php to get the result?

Try this.
Comments are in code.
It will loop through the keys and return the searched value.
$a = array('a'=>array('b'=>array('c'=>array('d'=>123,'s'=>4),'r'=>3),'q'=>2),'p'=>1);
$keys1 = array('a','b','c');
$keys2 = array('a','b');
$keys = $keys1; // set this as "search value"
$value = $a; // create a copy of original array. Maybe not needed?
Foreach($keys as $key){ // loop keys in search value
$value = $value[$key]; // overwrite $value with subarray of $value[$key]
}
Var_dump($value); // dump the search return.
https://3v4l.org/ZHBMa

Related

More efficient way to sort unique values from array of arrays by occurrences in PHP

What would be the most efficient PHP way to get unique values from an array of arrays and sort them by number of occurrences from most frequent to least?
Example input array:
Array
(
[0] => Array
(
[0] => A
[1] => B
[2] => C
[3] => D
)
[1] => Array
(
[0] => A
[1] => C
[2] => D
)
[2] => Array
(
[0] => C
[1] => F
[2] => X
)
)
Would result in this output array:
Array
(
[0] => C // 3
[1] => A // 2
[2] => D // 2
[3] => B // 1
[4] => F // 1
[5] => X // 1
)
The alphabetical order of values with same number of occurrences is not important.
So far I'm merging the array of arrays:
$all_posts = call_user_func_array( 'array_merge', $results );
Then creating a new array where values become keys. And values are the number of times they occur in the original array of arrays.
$posts_by_count = array();
foreach( $all_posts as $apost ) {
$posts_by_count[ $apost ] = 0;
foreach( $results as $tag_posts ) {
if( in_array( $apost, $tag_posts ) ) {
$posts_by_count[ $apost ]++;
}
}
}
Then I can sort by value
arsort($posts_by_count);
And create a new array where keys become values again.
$sorted_posts = array();
foreach($posts_by_count as $k => $v) {
$sorted_posts[] = $k;
}
pprint( $sorted_posts );
What would be a more efficient way to do that?
The simplest I can come up with is to start with the array_merge(), but using the splat (...) to merge all of the arrays. Then use the inbuilt array_count_values() to summarize the values and then arsort() to sort them...
$all_posts = array_merge(...$results );
$posts_by_count = array_count_values($all_posts);
arsort($posts_by_count);
This gives the output of...
Array
(
[C] => 3
[A] => 2
[D] => 2
[B] => 1
[F] => 1
[X] => 1
)
using
print_r(array_keys($posts_by_count));
gives...
Array
(
[0] => C
[1] => A
[2] => D
[3] => B
[4] => F
[5] => X
)
That's simple, first iterate to count occurences, finally use arsort() to sort it by value in descending order:
<?php
// sample data
$arr = [
['A', 'B', 'C', 'D'],
['A', 'C', 'D'],
['C', 'F', 'X']
];
// counting
$newArr = [];
foreach ($arr as $subarr) {
foreach ($subarr as $char) {
$newArr[$char] = (!array_key_exists($char, $newArr))
? 1
: $newArr[$char] = $newArr[$char] + 1;
}
}
// sort by value in DESC order
arsort($newArr);
// To get exactly what you want (without counting) just iterate $newArr and writ is as a $flatArr
$flatArr = [];
foreach ($newArr as $index => $item) {
$flatArr[] = $index;
}
// or with array_keys which _may_ be unstable #see: https://stackoverflow.com/q/10336363/1066240
$flatArrArrayKeys = array_keys($newArr);
// output
$newArrHr = print_r($newArr, 1);
$flatArrHr = print_r($flatArr, 1);
echo "<pre>OUTPUT:
With count:
$newArrHr
As flat array:
$flatArrHr
As flat array with array_keys()
$flatArrArrayKeys
";

Group associative row data based on shared column value

I have a multidimensional array like:
Array
(
[0] => Array
(
[division] => Mymensingh
[A] => 1
)
[1] => Array
(
[division] => Dhaka
[A] => 5
)
[2] => Array
(
[division] => Mymensingh
[B] => 2
[C] => 5
)
)
I need to find the rows with matching division values and merge them in one array.
From this array, I want the output as:
Array
(
[0] => Array
(
[division] => Mymensingh
[A] => 1
[B] => 2
[C] => 5
)
[1] => Array
(
[division] => Dhaka
[A] => 5
)
)
Keys in the subarrays can be different and the subarrays may have a differing number of elements.
I think it's relatively simple to just iterate through the array and continuously merge the entries separated by "division":
function mergeByDiscriminator($input, $discriminator = 'division') {
$result = [];
foreach ($input as $array) {
$key = $array[$discriminator];
$result[$key] = array_merge(
array_key_exists($key, $result) ? $result[$key] : [],
$array
);
}
return array_values($result);
}
$result = mergeByDiscriminator($input); // $input is your array
The only solution that I can think of is as below. Of course there might be other feasable solutions, but I am giving one from my end.
$array = array(
'0' => array (
'division' => 'Mymensingh',
'A' => 1
),
'1' => array (
'division' => 'Dhaka',
'A' => 5
),
'2' => array (
'division' => 'Mymensingh',
'B' => 2,
'C' => 5
),
);
$result = array();
foreach ($array as $arr) {
if (!is_array($result[$arr['division']])) $result[$arr['division']] = array();
foreach ($arr as $key => $value) {
$result[$arr['division']][$key] = $value;
}
}
echo "<pre>"; print_r($result);
The above code is giving you the desired output. Please give it a try.
Hope this helps.
This task is concisely completed with zero iterated function calls thanks to the null coalescing operator and the union operator.
Merge each iterated row with the pre-existing data in that keyed-group. If the keyed-group has not yet been encountered merge the row with an empty array.
The union operator is suitable/reliable in this case because it is writing one associative array into another associative array.
Language Construct Iteration: (Demo)
$result = [];
foreach ($array as $row) {
$result[$row['division']] = ($result[$row['division']] ?? []) + $row;
}
var_export(array_values($result));
Functional Iteration: (Demo)
var_export(
array_values(
array_reduce(
$array,
function($result, $row) {
$result[$row['division']] = ($result[$row['division']] ?? []) + $row;
return $result;
},
[]
)
)
);

Push data to elements in array in php

$array = array(array("a"=>1),array("a"=>2));
I need to push data to sub array element in $array,
End result must be as follow,
Array ( [0] => Array ( [a] => 1 [b] => 2 ) [1] => Array ( [a] => 2 [b] => 2 ) )
I used following ways .
foreach($array as &$a){ $a['b']=2;}
$result = array_map("pushdata",$array);
function pushdata($a){
$a['b']=2;
}
what is the most suitable and performance high way when $array consists of more than 1000 records ?
Here is an example using array_walk() to add a new key b to each sub-array:
$array = array(array('a' => 1), array('a' => 2));
array_walk($array, function(&$item, $key) {
$item['b'] = 2;
});
print_r($array);
/* outputs:
Array
(
[0] => Array
(
[a] => 1
[b] => 2
)
[1] => Array
(
[a] => 2
[b] => 2
)
)
*/
Here is an example for 5 items.
<?php
for($i = 1 ; $i<5 ; $i++){
$array[] = array("a"=>$i,"b"=>2);
}
print_r($array);
?>
See online
Use array_walk , to iterate over the array and array_push to push the element to each iteration.

Count instances of value/key in merged arrays and set value by count

I am looking at trying to do an array_merge with these arrays but I need to be able to count how many times a particular value in the array appears and give me that data back.
Here are the original arrays
Array
(
[0] => this
[1] => that
)
Array
(
[0] => this
[1] => that
[2] => some
)
Array
(
[0] => some
[1] => hello
)
Ultimately I would like it to look like this
Array
(
[this] => 2
[that] => 2
[some] => 2
[hello] = > 1
)
That would ultimately allow me to get the key and value I need. I tried 'array_unique` in this process but realized that I may not be able to count the instances of each array that they appear since this would just simple remove them all but one.
I tried something list this
$newArray = array_count_values($mergedArray);
foreach ($newArray as $key => $value) {
echo "$key - <strong>$value</strong> <br />";
}
but I am getting results like this
Array
(
[this] => 2
[that] => 2
[some] => 2
[hello] = > 1
[this] => 3
[that] => 3
[some] => 3
[hello] = > 2
[this] => 2
[that] => 2
[some] => 2
[hello] = > 1
)
Use array_count_values():
$a1 = array(0 => 'this', 1 => 'that');
$a2 = array(0 => 'this', 1 => 'that', 2 => 'some');
$a3 = array(0 => 'some', 1 => 'hello');
// Merge arrays
$test = array_merge($a1,$a2,$a3);
// Run native function
$check = array_count_values($test);
echo '<pre>';
print_r($check);
echo '</pre>';
Gives you:
Array
(
[this] => 2
[that] => 2
[some] => 2
[hello] => 1
)
EDIT: As noted by AlpineCoder:
"This will work only in the case of input arrays using numeric (or unique) keys (since array_merge will overwrite values for the same non-integer key)."
$res = array();
foreach ($arrays as $array) {
foreach ($array as $val) {
if (isset($res[$val])) {
$res[$val]++;
} else {
$res[$val] = 1;
}
}
}
As tyteen4a03 mentioned, use nested foreach loops:
$arr1 = array('foo', 'bar');
$arr2 = array('foo', 'bar', 'baz');
$arr3 = array('baz', 'bus');
$result = array();
foreach(array($arr1, $arr2, $arr3) as $arr) {
foreach ($arr as $value) {
if (!isset($result[$value])) {
$result[$value] = 0;
}
++$result[$value];
}
}
print_r($result);
The outer foreach goes through each set of items (i.e. each array) and the inner foreach loop goes through each item in each set. If the item isn't in the $result array yet, create the key there.
Result:
Array
(
[foo] => 2
[bar] => 2
[baz] => 2
[bus] => 1
)

PHP - Compare two array and remove both item in a specific index if either of the array have empty value

Refer to 2 array below:
$bar_arr =
Array
(
Array
(
[bar] => bar01.jpg
[position] => 1
)
Array
(
[bar] => bar02.jpg
[position] => 2
)
Array
(
[bar] => bar03.jpg
[position] => 3
)
)
$banner_arr =
Array
(
Array
(
[banner] =>
[position] => 1
)
Array
(
[banner] => banner02.jpg
[position] => 2
)
Array
(
[banner] => banner03.jpg
[position] => 3
)
)
$banner_arr[0][banner] don't have value, so I would like to remove this index. In the meantime$bar_arr[0][bar] would also be removed, I want to end up like this:
$bar_arr =
Array
(
Array
(
[bar] => bar02.jpg
[position] => 2
)
Array
(
[bar] => bar03.jpg
[position] => 3
)
)
$banner_arr =
Array
(
Array
(
[banner] => banner02.jpg
[position] => 2
)
Array
(
[banner] => banner03.jpg
[position] => 3
)
)
My question is how to compare this two array and remove both item in a specific index if either of the array have empty value.
Thanks
If you're just checking the value of banner and you assume that the two arrays are ordered identically, this is fairly simple (You might need to make a copy of banner_arr first ... not sure):
foreach ($banner_arr as $key => $banner) {
if (empty($banner['banner'])) {
unset($banner_arr[$key]);
unset($bar_arr[$key]);
}
}
More likely though, the order of the arrays can't be relied upon. In this case, just use an additional array of positions and track all the positions that need to be removed, and unset those:
$positions = array();
foreach ($banner_arr as $key => $banner) {
if (empty($banner['banner'])) {
$positions[] = $banner['position'];
unset($banner_arr[$key]);
}
}
then search through $bar_arr for corresponding positions:
foreach ($bar_arr as $key => $bar) {
if (in_array($bar['position'], $positions)) {
unset($bar_arr[$key]);
}
}
I'm assuming that both arrays are the same length and that the only possible missing values are in ['bar'] or ['banner'].
Basically I'd just loop through the array and store the valid values in new arrays;
$new_bar_arr = array();
$new_banner_arr = array();
$count = count($banner_arr);
$index = 0;
while($index < $count){
if(!empty($bar_arr[$index]['bar']) && !empty($banner_arr[$index]['banner'])){
$new_bar_arr[] = $bar_arr[$index];
$new_banner_arr[] = $banner_arr[$index];
}
$index++;
}
Assuming your count lines up like you've suggested:
$newArray = array_map( NULL, $banner_arr, $bar_arr );
foreach( $newArray as $key => $array ){
foreach( $array as $arr ){
if( $arr === NULL ){
unset( $newArray[$key] );
}
}
}
Even if it doesn't, I'd just make a new function and use array map still.

Categories