Dynamic create parent-child relationship array based on another table field values - php

There are 2 arrays Say
1. Groups
$groups = array("user", "account", "client")
2. Results
$results = array(
0 => array(
"user" => "U1",
"account" => "A1",
"client" => "C1"
),
1 => array(
"user" => "U1",
"account" => "A2",
"client" => "C1"
),
0 => array(
"user" => "U1",
"account" => "A3",
"client" => "C1"
),
0 => array(
"user" => "U1",
"account" => "A2",
"client" => "C2"
),
0 => array(
"user" => "U1",
"account" => "A1",
"client" => "C4"
),
0 => array(
"user" => "U1",
"account" => "A1",
"client" => "C5"
),
0 => array(
"user" => "U1",
"account" => "A2",
"client" => "C5"
)
) ;
I want following OUTPUT
$output = array(
"U1" => array(
"A1" => array(C1,C4,C5),
"A2" => array(C1,C2,C5),
"A3" => array(C1)
)
);
The Groups array values are dynamic and may be any order. I want output in order the first value of groups array is the parent element of Output array and second value of group array is the child of parent Output array and so on.

I hope you are using PHP greater or equal to 5.6. There we have ... (splat operator) that will come really handy:
$output = [];
array_map(function (...$keys) use (&$output) {
// Pop the last key, because it is actually a value.
$value = array_pop($keys);
// Prepare "element" to assign the value to using keys and references.
$element = &$output;
while($key = array_shift($keys)) {
if (!isset($element[$key])) {
$element[$key] = [];
}
$element = &$element[$key];
}
$element[] = $value;
}, ...array_map(function ($group) use ($results) {
return array_column($results, $group);
}, $groups));
Here is working demo.
In short, we take advantage of the ability of array_map to take any number of arrays as arguments and traverse them kinda parallelly.

Simply make a foreach loop like this
$new = array();
foreach($results as $key=>$value){
$new[$value["user"]][$value["account"]][] = $value["client"];
}
print_r($new);
live demo : https://eval.in/857969
Using $groups : https://eval.in/857970
$new = array();
foreach($results as $key=>$value){
$new[$value[$groups[0]]][$value[$groups[1]]][] = $value[$groups[2]];
}
Example for multiple user's : https://eval.in/857973
Update
For dynamic groups array : You can use eval if you are not interacting user input here. : https://eval.in/858306

Related

how to make a new php array with merge fields and change name attributes

i am try change a array in php in laravel. i have a nested array with duplicate fields. but there is one i what to change the name timestamp. how can i do this?
$consumos = array(
array(
"device" => "EA1",
"timestamp" => "2020-01-01 21:00:00",
"value" => 4,
),
array(
"device" => "EA1",
"timestamp" => "2020-01-01 07:00:00",
"value" => 4,
),
array(
"device" => "EA2",
"timestamp" => "2022-01-01 12:00:00",
"value" => 2,
),
array(
"device" => "EA2",
"timestamp" => "2022-01-01 13:00:00",
"value" => 2,
),
);
i what to make something like this:
array(
"device" => "EA1",
"start" => "2020-01-01 21:00:00",
"end" => "2020-01-01 07:00:00",
"value" => 4,
),
array(
"device" => "EA1",
"start" => "2022-01-01 12:00:00",
"end" => "2022-01-01 13:00:00",
"value" => 2,
),
thanks in advance!
I'm not sure if the 'grouping key' is the device, the value, or both, but anyway.
I'd use a for-loop to map it, then drop the keys from the map:
$map = [];
foreach ($consumos as $consumo) {
$key = $consumo["device"]; // or value, or both
if (isset($map[$key])) {
$map[$key]["end"] = $consumo["timestamp"];
} else {
$map[$key] = [
"device" => $consumo["device"],
"start" => $consumo["timestamp"],
"value" => $consumo["value"],
];
}
}
$return = [];
foreach ($map as $ret) {
$return[] = $ret;
}
If you know you'll always have an even number of events per key, and there can be more than two events per key, you could merge both foreach, and make it so when you add an 'end' timestamp, you also add the element to $return and drop the element from the map (allowing it to be inserted again when it shows up).
$map = [];
$return = [];
foreach ($consumos as $consumo) {
$key = $consumo["device"]; // or value, or both
if (isset($map[$key])) {
$map[$key]["end"] = $consumo["timestamp"];
$return[] = $map[$key];
unset($map[$key]);
} else {
$map[$key] = [
"device" => $consumo["device"],
"start" => $consumo["timestamp"],
"value" => $consumo["value"],
];
}
}
first, try using a grouping array based on the device name, you can use this page for sample algorithm: url
then with a foreach loop, you can get each timestamp of the device name and you can add devices to an array like this :
$newArray[] = [
// other fields ...
"start" => $item[0]['timestamp'],
"end" => $item[1]['timestamp'],
]

Intersection of one multidimensional arrays in PHP

I have the following array :
$output = array(
1507073550 => array(
0 => array(
"userid" => "1507073550"
"username" => "ma_alikhani"
"type" => "comment"
"profile_image" => "https://instagram.fgbb2-1.fna.fbcdn.net/v/t51.2885-19/s150x150/75538099_557824008392923_8054831368279949312_n.jpg?_nc_ht=instagram.fgbb2-1.fna.fbcdn.net&_nc_ohc"
)
1 => array(
"userid" => "11863258101"
"username" => "rasouli680"
"type" => "comment"
"profile_image" => "https://instagram.fgbb2-1.fna.fbcdn.net/v/t51.2885-19/s150x150/70326284_949495768737898_5241573836020776960_n.jpg?_nc_ht=instagram.fgbb2-1.fna.fbcdn.net&_nc_ohc"
)
2 => array(
"userid" => "16528062"
"username" => "alireza"
"type" => "comment"
"profile_image" => "https://instagram.fgbb2-1.fna.fbcdn.net/v/t51.2885-19/s150x150/70597112_740563976416368_5253996423334068224_n.jpg?_nc_ht=instagram.fgbb2-1.fna.fbcdn.net&_nc_ohc"
)
)
16528062 => array(
0 => array(
"userid" => "16528062"
"username" => "alireza"
"type" => "comment"
"profile_image" => "https://instagram.fgbb2-1.fna.fbcdn.net/v/t51.2885-19/s150x150/70597112_740563976416368_5253996423334068224_n.jpg?_nc_ht=instagram.fgbb2-1.fna.fbcdn.net&_nc_ohc"
)
1 => array(
"userid" => "1507073550"
"username" => "ma_alikhani"
"type" => "comment"
"profile_image" => "https://instagram.fgbb2-1.fna.fbcdn.net/v/t51.2885-19/s150x150/75538099_557824008392923_8054831368279949312_n.jpg?_nc_ht=instagram.fgbb2-1.fna.fbcdn.net&_nc_ohc"
)
)
)
and I want to intersection of keys of this array. get first key "1507073550" and second key "16528062" and intersect all of their data.
it's not always have 2 keys, it might have +2 keys, i wrote this code but I'm getting array to string conversion error.
$keys = array_keys($output);
foreach ($keys as $index => $values)
{
$current_value = $output[$values]; // or $current_value = $a[$keys[$index]];
$next_key = next($keys);
$next_value = $output[$next_key] ?? null; // for php version >= 7.0
$a[] = array_intersect_assoc($current_value,$next_value);
}
and I'm expecting this result :
array(
0 => array(
"userid" => "1507073550"
"username" => "ma_alikhani"
"type" => "comment"
"profile_image" => "https://instagram.fgbb2-1.fna.fbcdn.net/v/t51.2885-19/s150x150/75538099_557824008392923_8054831368279949312_n.jpg?_nc_ht=instagram.fgbb2-1.fna.fbcdn.net&_nc_ohc"
)
1 => array(
"userid" => "16528062"
"username" => "alireza"
"type" => "comment"
"profile_image" => "https://instagram.fgbb2-1.fna.fbcdn.net/v/t51.2885-19/s150x150/70597112_740563976416368_5253996423334068224_n.jpg?_nc_ht=instagram.fgbb2-1.fna.fbcdn.net&_nc_ohc"
)
)
I really don't know how to do it !
I'd be appreciated for your helps.
function intersect(array $src, array $keys)
{
// Require that both $src and $keys have data
if (!$src || !$keys) {
return [];
}
// Hold the users for each key in $keys
$sets = [];
// Store the users from $src to $sets as dictated by $keys
foreach ($keys as $key) {
if (isset($src[$key])) {
// Re-key the list of users with their user id
$userIds = array_column($src[$key], 'userid');
$sets[$key] = array_combine($userIds, $src[$key]);
}
}
if (count($sets) !== count($keys)) {
// Up to you if you want to require that all keys must be valid/present in the $src
}
// Get the users present in all of the set dictated by $keys
$users = call_user_func_array('array_intersect_key', $sets);
return $users;
};
To use:
$output = [ ... ]; // $ouput in the question
$keys = [1507073550, 16528062]; // see question
$users = intersect($output, $keys);

PHP multidimensional array search key by value

For example a multidimensional array like an example below
$arr = array(
[H1] => array(
"name" => "A"
"title" => "T1"
)
[H2] => array(
"name" => "B"
"title" => "B1"
)
)
Let's say I would like to search name which equals to A in $arr and if it's matched, the searching should return the key which is H1
How can I do that in php ?
I tried array_keys($arr, "A") but it returns me with an array instead of the key.
This may help -
$arr = array(
'H1' => array(
"name" => "A",
"title" => "T1",
),
'H2' => array(
"name" => "B",
"title" => "B1",
)
);
// Generate a new array with 'keys' and values in 'name'
$new = array_combine(array_keys($arr), array_column($arr, 'name'));
// Search in that new array
$search = array_search('A', $new);
var_dump($search);
Output
string(2) "H1"
Demo
Another simple way would be -
$serach= false;
foreach($arr as $key => $val) {
if($val['name'] == 'A') {
$search= $key;
break;
}
}
var_dump($search);

PHP - Get key value from other key

I have the following array:
$array = Array(
"0" => Array (
"id" => 1081,
"name" => "John"
),
"1" => Array (
"id" => 1082,
"name" => "Matt"
),
"2" => Array (
"id" => 1083,
"name" => "Roger"
)
);
Is there anyway I can get name if I only know the id but without having to iterate through the array?
For PHP >= 5.5.0:
$id = 1082;
$result = array_column($array, 'name', 'id')[$id];
As Barmar points out, to get an array that is easy to use with id as the index:
$id = 1082;
$result = array_column($array, 'name', 'id');
echo $result[$id];
You can make an associative array that refers to the same elements, then use that:
function make_assoc(&$array, $keyname) {
$new_array = array();
foreach ($array as &$elt) {
$new_array[$elt[$keyname]] = $elt;
}
return $new_array;
}
$assoc_array = make_assoc($array, 'id');
Now you can use $assoc_array[1083] to access the third item in the original array. And since this returns an array of references, modifying that will also modify the element of the original array.
You can use array_map to search into your array if your PHP < 5.5.0 and you don't have array_column:
<?php
$array = Array(
"0" => Array (
"id" => 1081,
"name" => "John"
),
"1" => Array (
"id" => 1082,
"name" => "Matt"
),
"2" => Array (
"id" => 1083,
"name" => "Roger"
)
);
$find = 1082;
$value = '';
$arr = array_map(function($n) use ($find, &$value) {if ($n['id'] == $find) $value = $n['name']; }, $array);
print_r($value);
?>

Put nested array into one array

Suppose i have a array like this :
Array(
'1' => Array(
"ID" => 1,
"Name" => "name 1"
),
'2' => Array (
Array(
"ID" => 2,
"Name" => "name 2"
)
),
'3' => Array(
Array(
Array(
Array(
"ID" => 3,
"Name" => "name3"
)
)
),
'4' => Array (
Array {
"ID" => 4,
"Name" => "name 4"
),
Array(
"ID" => 5,
"Name" => "name 5"
),
Array(
"ID" => 6,
"Name" => "name 6"
)
);
number of sub-arrays is not ordered it may be 3, 4 or 5 etc...
and i wanted to get :
Array(
Array( "ID" => 1, "Name" => "name 1"),
Array( "ID" => 2, "Name" => "name 2"),
Array( "ID" => 3, "Name" => "name 3"),
Array( "ID" => 4, "Name" => "name 4"),
Array( "ID" => 5, "Name" => "name 5"),
Array( "ID" => 6, "Name" => "name 6"));
Is there an easy way to do this ?
EDIT :
Edited the above array to add :
'4' => Array (
Array {
"ID" => 4,
"Name" => "name 4"
),
Array(
"ID" => 5,
"Name" => "name 5"
),
Array(
"ID" => 6,
"Name" => "name 6"
)
);
which aren't nested but i still want them to be in my final array.
Thanks.
//Assuming your data is in $in
$out=array();
foreach($in as $k=>$v) {
while ((is_array($v)) && (isset($v[0]))) $v=$v[0];
//See below for next line
$out[]=$v;
}
print_r($out);
With the marked line being either $out[$k]=$v; or $out[]=$v; depending on wether you want to keep the 1st-level keys. In your desired output you do not ,so use the shown version
Edit
With you changed input array, you need to do something like
function addtoarray($inarray, &$outarray) {
foreach ($inarray as $i) {
if (!is_array($i)) continue;
if (isset($i['ID'])) $outarray[]=$i;
else addtoarray($i,$outarray);
}
}
$out=array();
addtoarray($in,$out);
print_r($out);
This was tested against your new input data
You could recurse through the array and check for the ID field.
function combine_array(array $src, array &$dest)
{
if( isset( $src['ID'] ) ) {
$dest[] = $src;
return;
}
foreach( $sub in $src ) {
combine_array( $sub, $dest );
}
}
Just wrote this off the top of my head, no testing, so it might have a few problems. But that's the basic idea.
This may work for you, assuming $array is the variable and php 5.3
//process
$array = array_map(function($block) {
$return = '';
foreach ($block as $sub) {
if (true === isset($sub['ID']) {
$return = $block;
break;
}
}
return $block;
}, $array);
array_filter($array); //remove empty elements
Wrote up a quick recursive function. You'll need to write any appropriate error handling and check the logic, since a discrepancy in your data could easily turn this into an infinite loop:
$output = array();
foreach ( $data as $d ) {
$output[] = loop_data( $d );
}
function loop_data( $data ) {
// Check if this is the right array
if( ! array_key_exists( "ID", $data ) ) {
// Go deeper
$data = loop_data( $data[0] );
}
return $data;
}

Categories