Array reduce with associative array - php

I have an array like this
$filter_array = Array
(
[0] => Array
(
[fv_id] => 1
[fv_value] => Red
[filter_id] => 1
[filter_name] => Color
)
[1] => Array
(
[fv_id] => 2
[fv_value] => Blue
[filter_id] => 1
[filter_name] => Color
)
)
I would like to reduce the array by having filter_name and filter_id on top of array which is similar for all arrays.
$newArray = array_reduce($filter_array,function($carry,$item){
$allFilterValues[] = array(
'fv_id' => $item['fv_id'],
'fv_value' => $item['fv_value'],
);
$formated_array = array(
'filter_id' => $item['filter_id'],
'filter_name' => $item['filter_name'],
'filter_values' => $allFilterValues
);
return $formated_array;
});
But I am just getting the last array iterations value on filter_values
Array
(
[filter_id] => 1
[filter_name] => Color
[filter_values] => Array
(
[0] => Array
(
[fv_id] => 2
[fv_value] => Blue
)
)
)
But I want the array be like this.
Array
(
[filter_id] => 1
[filter_name] => Color
[filter_values] => Array
(
[0] => Array
(
[fv_id] => 1
[fv_value] => Red
),
[1] => Array
(
[fv_id] => 2
[fv_value] => Blue
)
)
)

On each iteration of array_reduce callback function must return current $carry value:
$newArray = array_reduce($filter_array,function($carry,$item){
// create key so as to distinct values from each other
$key = $item['filter_id'] . '-' . $item['filter_name'];
// check if created key exists in `$carry`,
// if not - we init it with some data
if (empty($carry[$key])) {
$carry[$key] = [
'filter_id' => $item['filter_id'],
'filter_name' => $item['filter_name'],
'filter_values' => []
];
}
// add values to `filter_values`
$carry[$key]['filter_values'][] = [
'fv_id' => $item['fv_id'],
'fv_value' => $item['fv_value'],
];
return $carry;
}, []);
// if you want to reindex `$newArray` from 0:
$newArray = array_values($newArray);
Update: if and only if in your $filter_array values of 'filter_id' and 'filter_name' are always the same you can simplify your code:
$newArray = [];
$first = true;
foreach ($filter_array as $item) {
if ($first) {
$first = false;
$newArray = [
'filter_id' => $item['filter_id'],
'filter_value' => $item['filter_name'],
'filter_values' => []
];
}
$newArray['filter_values'][] = [
'fv_id' => $item['fv_id'],
'fv_value' => $item['fv_value'],
];
}
echo'<pre>',print_r($newArray),'</pre>';

Related

Compare values using strpos - PHP

I am trying to return the user_id if value matches with any comma separated value, I am using strpos but I don't why is it not working with 3rd case:
To Compare: (This value is stored in $myArray variable)
Array
(
[0] => cloud
[1] => ai
[2] => test
)
Compare with: (This value is stored in $array_meta_values variable)
Array
(
[0] => Array
(
[tags] => cloud,ai
[user_id] => 1
)
[1] => Array
(
[tags] => cloud,ai,test
[user_id] => 108
)
[2] => Array
(
[tags] => storage,backup,ai
[user_id] => 101
)
)
function searchForId($meta_value, $array)
{
foreach ($array as $key => $val) {
if (strpos($val['tags'], $meta_value)) {
return $val['user_id'];
}
}
}
foreach ($myArray as $usertags) {
$userids[] = searchForId($usertags, $array_meta_values);
}
print_r($userids);
Getting this Output:
Array
(
[1] => 1
[2] => 108
)
It was supposed to add 101 as third element in output array but don't know why it is not working.
Any help appreciated.
Hi so I tried to replicate you question,
$existing = ['cloud', 'ai', 'test'];
$checker = [
array(
"tags" => "cloud,ai",
"user_id" => 1
),
array(
"tags" => "cloud,ai,test",
"user_id" => 108
),
array(
"tags" => "storage,backup,ai",
"user_id" => 101
)
];
function searchForId($meta_value, $array)
{
$ret_array = [];
foreach ($array as $val) {
$et = explode(",", $val['tags']);
if (in_array($meta_value, $et)) {
$ret_array[] = $val['user_id'];
}
}
return $ret_array;
}
foreach ($existing as $usertags) {
$userids[$usertags][] = searchForId($usertags, $checker);
}
echo "<pre>";
print_r($userids);
Is this what you looking for?
Your question is quite unclear, but I'll try with this one:
<?php
$myArray = array('cloud', 'ai', 'test');
$array_meta_values = array(
array(
'tags' => 'cloud,ai',
'user_id' => 1,
),
array(
'tags' => 'cloud,ai,test',
'user_id' => 108,
),
array(
'tags' => 'storage,backup,ai',
'user_id' => 101,
),
);
$userids = [];
foreach ($myArray as $value) {
foreach ($array_meta_values as $array) {
$arrayValues = explode(',', $array['tags']);
if (in_array($value, $arrayValues)) {
$userids[$value][] = $array['user_id'];
}
}
}
echo '<pre>';
print_r($userids);
Output:
Array
(
[cloud] => Array
(
[0] => 1
[1] => 108
)
[ai] => Array
(
[0] => 1
[1] => 108
[2] => 101
)
[test] => Array
(
[0] => 108
)
)

Group subsets of data in 3-level array by identifying column

I've this type of array in PHP:
Array(
[100] => Array(
[1] => Array (
[AVA_Date] => 2019-04-18
[ROO_Id] => 100
[RAT_Id] => 9
)
[2] => Array (
[AVA_Date] => 2019-04-20
[ROO_Id] => 100
[RAT_Id] => 10
)
[4] => Array (
[AVA_Date] => 2019-04-21
[ROO_Id] => 100
[RAT_Id] => 10
)
[7] => Array (
[AVA_Date] => 2019-04-22
[ROO_Id] => 100
[RAT_Id] => 9
)
)
)
I would like to merge items on ROO_Id and RAT_Id.
Then, for the AVA_Date, I need to list them under a new array in the current array.
So, the desired output is:
Array(
[100] => Array(
[0] => Array (
[AVA_Date] => Array (
[0] => 2019-04-18
[1] => 2019-04-22
)
[ROO_Id] => 100
[RAT_Id] => 9
)
[1] => Array (
[AVA_Date] => Array (
[0] => 2019-04-20
[1] => 2019-04-21
)
[ROO_Id] => 100
[RAT_Id] => 10
)
)
)
Here what I have tried:
$newArrOtherRooms = array_reduce($newArr, function($acc, $val) {
$room = array_search($val['ROO_Id'], array_column($acc, 'ROO_Id'));
$rate = array_search($val['RAT_Id'], array_column($acc, 'RAT_Id'));
if($rate == $room && $room > -1) {
array_push($acc[$room]['AVA_Date'], $val['AVA_Date']);
}
else {
$new_arr = $val;
$new_arr['AVA_Date'] = [$val['AVA_Date']];
array_push($acc, $new_arr);
}
return $acc;
},[]);
But it doesn't work like I want.
There are a couple of issues with your code. Firstly, you need to wrap the array_reduce with a foreach over the outer level of $newArr. Secondly, your call to array_search doesn't consider the fact that a ROO_Id or RAT_Id value might exist more than once in the array, as it only returns the first key at which it finds the value. To work around this, you can use array_keys to get an array of key values for each ROO_Id and RAT_Id value, and then take the intersection of those two arrays using array_intersect to see if both are present in the same element. If so, you update that element, otherwise you create a new one:
foreach ($newArr as $key => $array) {
$newArrOtherRooms[$key] = array_reduce($array, function($acc, $val) {
$room = array_keys(array_column($acc, 'ROO_Id'), $val['ROO_Id']);
$rate = array_keys(array_column($acc, 'RAT_Id'), $val['RAT_Id']);
$common = array_intersect($room, $rate);
if(!empty($common)) {
array_push($acc[current($common)]['AVA_Date'], $val['AVA_Date']);
}
else {
$new_arr = $val;
$new_arr['AVA_Date'] = [$val['AVA_Date']];
array_push($acc, $new_arr);
}
return $acc;
},[]);
}
print_r($newArrOtherRooms);
Output:
Array(
[100] => Array(
[0] => Array (
[AVA_Date] => Array (
[0] => 2019-04-18
[1] => 2019-04-22
)
[ROO_Id] => 100
[RAT_Id] => 9
)
[1] => Array (
[AVA_Date] => Array (
[0] => 2019-04-20
[1] => 2019-04-21
)
[ROO_Id] => 100
[RAT_Id] => 10
)
)
)
Demo on 3v4l.org
There is absolutely no reason to be making all of those iterated function calls.
Use a nested loop to iterate the subset of data for each room, group on the room "rate id", and push all "available date" values into a subarray in the respective group. When the subset of data is fully iterated, push its grouped data into the result array.
Code: (Demo)
$result = [];
foreach ($newArr as $rooId => $rows) {
$groups = [];
foreach ($rows as $row) {
if (!isset($groups[$row['RAT_Id']])) {
$row['AVA_Date'] = (array) $row['AVA_Date'];
$groups[$row['RAT_Id']] = $row;
} else {
$groups[$row['RAT_Id']]['AVA_Date'][] = $row['AVA_Date'];
}
}
$result[$rooId] = array_values($groups);
}
var_export($result);
Output:
array (
100 =>
array (
0 =>
array (
'AVA_Date' =>
array (
0 => '2019-04-18',
1 => '2019-04-22',
),
'ROO_Id' => 100,
'RAT_Id' => 9,
),
1 =>
array (
'AVA_Date' =>
array (
0 => '2019-04-20',
1 => '2019-04-21',
),
'ROO_Id' => 100,
'RAT_Id' => 10,
),
),
)

Array inside array or nested array

I have an array like below: all the values I am getting one array only, but I don't want this way. This is the best way to do so, in php or jQuery both languages are ok for me
Array
(
[0] => Array
(
[val] => facebook
)
[1] => Array
(
[val] => snapchat
)
[2] => Array
(
[val] => instagram
)
[3] => Array
(
[expenses] => 986532
)
[4] => Array
(
[expenses] => 45456
)
[5] => Array
(
[expenses] => 56230
)
[6] => Array
(
[social_id] => 15
)
[7] => Array
(
[social_id] => 16
)
[8] => Array
(
[social_id] => 17
)
)
and I want to output like this..
$result = array(
array(
"val" => "Facebook",
"expenses" => "84512",
"social_id" => 1
),
array(
"val" => "Instagram",
"expenses" => "123",
"social_id" => 2
)
);
but this should be dynamic, the length of the above array can be varies
You can merge the arrays to one and use array_column to get all vals or expenses in a separate array.
Then foreach one array and build the new array with the key.
//$a = your array
// Grab each column separate
$val = array_column($a, "val");
$expenses= array_column($a, "expenses");
$social_id = array_column($a, "social_id");
Foreach($val as $key => $v){
$arr[] = [$v, $expenses[$key], $social_id[$key]];
}
Var_dump($arr);
https://3v4l.org/nVtDf
Edit updated with the 'latest' version of the array. My code works just fine with this array to without any changes.
to get that array style you can do it by hand for each array
function test(array ...$arr)
{
$result = array();
foreach ($arr as $key => $pair) {
foreach ($pair as $item => $value) {
$result[$item] = $value;
}
}
return $result;
}
$arr1 = test( ['facebook' => 1], ['expenses' => 100]);
print_r($arr1);
/* Array (
[facebook] => 1,
[expenses] => 100
)
*/
$arr2 = test( $arr1, ['more info' => 'info'] );
print_r($arr2);
/* Array (
[facebook] => 1,
[expenses] => 100,
[more info] => info
)
*/
you can pass it any number of
['Key' => 'Pair']
array('Key' => 'Pair')
or even a previous made array and it will add them up into 1 big array and return it

add new element to an N-level Multidimentional array in PHP

I have an N-level Multidimentional array like this:
Array
(
[0] => Array
(
[id] => 7_cat
[text] => cat1
[children] => Array
(
[0] => Array
(
[id] => 9_cat
[text] => cat3
)
)
)
[1] => Array
(
[id] => 8_cat
[text] => cat2
)
[2] => Array
(
[id] => 13_cat
[text] => cat4
)
)
and i have an array of index like this:
Array
(
[0] => 0
[1] => children
[2] => 0
[3] => id
)
so i want to add a new element in first array in these depth. in this example i want to add a new element in $firstarray[0]['children'][0]['id'].
How can i do it?
thanks alot
Do Like this
Here $oldArray is your first array
$indexArray=Array
(
[0] => 0
[1] => children
[2] => 0
[3] => id
);
$indexForold=[];
foreach($indexArray as $indx){
$indexForold=$indexForold[$indx];
}
$oldArray[$indexForold]=$myVal;
The solution is, while traversing the array use reference to keep a reference to the current array element.
Here $nArr is your n-dimensional array and $indexArr is your index array.
And don't forget to replace <YOUR_VALUE> with your desired value.
So your code should be like this:
$arrLength = count($indexArr);
$tmpArr = null;
$i = 0;
for(; $i < $arrLength - 1; ++$i){
if($tmpArr == null){
$tmpArr = &$nArr[$indexArr[$i]];
}else{
$tmpArr = &$tmpArr[$indexArr[$i]];
}
}
$tmpArr[$indexArr[$i]] = <YOUR_VALUE>;
// now display the n-dimensional array
echo "<pre>";
print_r($nArr);
echo "</pre>";
You can try something like this...
$array = [
[
'id' => '7_cat',
'text' => 'cat1',
'children' => [
[
'id' => '9_cat',
'text' => 'cat3'
]
]
],
[
'id' => '8_cat',
'text' => 'cat2'
],
[
'id' => '13_cat',
'text' => 'cat4'
]
];
$multIndexValue = function (array $indexList, array $searchArray) {
$result = $searchArray;
foreach ($indexList as $index) {
$result = $result[$index];
}
return $result;
};
$search = [0, 'children', 0, 'id'];
$result = $multIndexValue($search, $array); // string(5) "9_cat"

How do I generate a flat array of indexes from a multi dimensional array?

I have the following array from PHP:
Array
(
[0] => Array
(
[ContractExhibitsData] => Array
(
[id] => 2
[exhibit_id] => 2
[parent_id] =>
)
[children] => Array
(
[0] => Array
(
[ContractExhibitsData] => Array
(
[id] => 98
[exhibit_id] => 2
[parent_id] => 2
)
[children] => Array
(
[0] => Array
(
[ContractExhibitsData] => Array
(
[id] => 99
[exhibit_id] => 2
[parent_id] => 98
)
[children] => Array
(
)
)
[1] => Array
(
[ContractExhibitsData] => Array
(
[id] => 100
[exhibit_id] => 2
[parent_id] => 98
)
[children] => Array
(
)
)
)
)
)
)
);
It is essentially a tree array, consisting of nodes with child nodes with more data. I want to iterate over this array using a recursive function to generate an array like this:
$return = Array
(
[2] => '1.',
[98] => '1.1.',
[99] => '1.1.1.',
[100] => '1.1.2.'
);
And so forth. Basically, it will be a bunch of Key-Value pairs where the array key is the 'id' of the element in ContractExhibitsData and the value is the numerical index.
I have the following function that I have been tinkering with, but it isn't getting me quite where I need to be.
private function getIndexes($data, $prefix = null) {
$indexes = array();
$count = 0;
if ($prefix) {
$prefix = $prefix . '.';
}
if (!empty($data['children'])) {
foreach($data['children'] as $child) {
$count++;
$indexes[$child['ContractExhibitsData']['id']] = $prefix.$count;
if (is_array($child['children']) && !empty($child['children'])) {
$subIndex = $this->getIndexes($child, $prefix.$count);
return $subIndex;
}
}
}
return $indexes;
}
Got it! See the working version here.
<?php
function getIndexes($data, $prefix = '') {
$indexes = array();
$count = 1;
if (!empty($prefix)) {
$prefix = $prefix . '.';
}
foreach ($data as $dataItem) {
$item = $dataItem['ContractExhibitsData'];
$index = $prefix.$count;
$indexes[$item['id']] = $index;
if(!empty($dataItem['children'])) {
$indexes = array_merge_recursive($indexes,getIndexes($dataItem['children'],$index));
}
$count++;
}
return $indexes;
}
$yourArray = array
(
0 => array (
'ContractExhibitsData' => array
(
'id' => 2,
'exhibit_id' => 2,
'parent_id' => null
),
'children' => array
(
0 => array
(
'ContractExhibitsData' => array
(
'id' => 98,
'exhibit_id' => 2,
'parent_id' => 2
),
'children' => array
(
0 => array
(
'ContractExhibitsData' => array
(
'id' => 99,
'exhibit_id' => 2,
'parent_id' => 98
),
'children' => array()
),
1 => array
(
'ContractExhibitsData' => array
(
'id' => 100,
'exhibit_id' => 2,
'parent_id' => 98
),
'children' => array ()
)
)
)
)
)
);
$result = getIndexes($yourArray);
var_dump($result);
One of your problems was that you had a return in your loop, thus breaking your loop. Also, you added null as a string since that was the default setting of your $prefix. You alos never iterated over the initial array but always just the children.

Categories