Converting a One-Dimensional Array into a Nested Array Using Relationship Keys - php

Say I have an array with keys representing id and values representing parent:
4 => 0
2 => 0
5 => 2
6 => 5
8 => 0
9 => 0
10 => 8
12 => 0
13 => 0
14 => 0
18 => 7
19 => 18
20 => 19
21 => 20
22 => 21
23 => 22
24 => 23
28 => 20
7 => 5
You could also read this as an object:
{
id : 4,
parent : 0
} // etc...
The multidimensional array I'd want to achieve from this would be:
4 => 0
2 => 5
=> 6
=> 7
=> 18
=> 19
=> 20
=> 21
=> 22
=> 23
=> 24
=> 28
8 => 10
9 => 0
12 => 0
13 => 0
14 => 0
How would I go about doing this?

If you write a little helper function to rework your data to a structure similar to:
$input = array(
array('id' => '4', 'parent' => '0'),
// ...
);
which could be achieved with something like:
$data = array_map(function ($entry) {
list($id, $parent) = array_map('trim', explode('=>', $entry));
return array(
'id' => $id,
'parent' => $parent
);
}, explode("\n", $data));
you could then use a function I used in a similar question:
function flatToNested($d, $r = 0, $p = 'parent', $k = 'id', $c = 'children') {
$m = array();
foreach ($d as $e) {
isset($m[$e[$p]]) ?: $m[$e[$p]] = array();
isset($m[$e[$k]]) ?: $m[$e[$k]] = array();
$m[$e[$p]][] = array_merge($e, array($c => &$m[$e[$k]]));
}
return $m[$r];
}
to produce a nested array with:
$nested = flatToNested($data);
demo: http://codepad.viper-7.com/HAZxaA

Related

Group rows of data by column value then store nested data, first and last occurrences, and counts within each group

I am trying to split an array of space-delimited strings, group by a particular column, then store the data within each group in a more convenient structure.
Sample data:
$dataArray = [
0 => "AAAAA 2023 01 25 01:04:00 ID:20fjrjeZZ",
1 => "AAAAA 2023 01 25 01:18:08 ID:13454B43A",
2 => "AAAAA 2023 01 25 02:00:02 ID:18f5hjeWe",
3 => "AAAAA 2023 01 25 04:10:13 ID:13454B43A",
4 => "BBBBB 2023 01 25 01:44:10 ID:Xj74320fj",
5 => "BBBBB 2023 01 25 07:08:58 ID:13454B43A",
6 => "BBBBB 2023 01 25 08:40:52 ID:Ftzkk800Y",
7 => "BBBBB 2023 01 25 14:10:13 ID:18f5hjeWe"
];
I split the rows on the space with:
$lines = explode(' ', $dataArray);
Then I want to push the individual parts (AAAA, 2023, 01, ...) into an array.
foreach($dataArray as $parts){
$spotArray[] = $parts[$parts][0];
$yearArray[] = $parts[$parts][1];
// ...
}
Then build a new structure with the new array parts:
foreach($dataArray as $key => $value){
$desiredArray[] = $spotArray[["user"[$yearArray[$hourArray]]], "first"[/** ... */]];
//...
}
Expected result:
$desiredArray = [
"AAAAA" => [
"user" => [
"ID:20fjrjeZZ" => ["01:04:00"],
"ID:13454B43A" => ["01:18:08", "04:10:12"],
"ID:18f5hjeWe" => ["02:00:02"]
],
"first" => "01:04:00",
"last" => "04:10:12",
"totaUser" => 3,
"totalAccess" => 4
],
"BBBBB" => [
"user" => [
"ID:Xj74320fj" => ["01:44:10"],
"ID:13454B43A" => ["07:08:58"],
"ID:Ftzkk800Y" => ["08:40:52"],
"ID:18f5hjeWe" => ["14:10:13"]
],
"first" => "01:44:10",
"last" => "14:10:13",
"totaUser" => 4,
"totalAccess" => 4
]
];
It is not at all necessary to run two loops.
Parse the space-delimited strings in your array and build/overwrite/sum as you iterate.
Code: (Demo)
$result = [];
foreach ($dataArray as $row) {
[$group, $y, $m, $d, $t, $id] = explode(' ', $row);
$result[$group]['user'][$id][] = $t; // accumulate nested elements
$result[$group]['first'] ??= $t; // only store the first occurrence
$result[$group]['last'] = $t; // keep overwriting each time
$result[$group]['totaluser'] = count($result[$group]['user']); // count what is accumulated
$result[$group]['totalAccess'] = ($result[$group]['totalAccess'] ?? 0) + 1; // increment
}
var_export($result);
You can even safely remove the unused $y, $m, and $d declarations if you wish. (Demo)
Output (from either snippet)
array (
'AAAAA' =>
array (
'user' =>
array (
'ID:20fjrjeZZ' =>
array (
0 => '01:04:00',
),
'ID:13454B43A' =>
array (
0 => '01:18:08',
1 => '04:10:13',
),
'ID:18f5hjeWe' =>
array (
0 => '02:00:02',
),
),
'first' => '01:04:00',
'last' => '04:10:13',
'totaluser' => 3,
'totalAccess' => 4,
),
'BBBBB' =>
array (
'user' =>
array (
'ID:Xj74320fj' =>
array (
0 => '01:44:10',
),
'ID:13454B43A' =>
array (
0 => '07:08:58',
),
'ID:Ftzkk800Y' =>
array (
0 => '08:40:52',
),
'ID:18f5hjeWe' =>
array (
0 => '14:10:13',
),
),
'first' => '01:44:10',
'last' => '14:10:13',
'totaluser' => 4,
'totalAccess' => 4,
),
)
You can find the answer to your question here
<?php
$dataArray = [
0 => "AAAAA 2023 01 25 01:04:00 ID:20fjrjeZZ",
1 => "AAAAA 2023 01 25 01:18:08 ID:13454B43A",
2 => "AAAAA 2023 01 25 02:00:02 ID:18f5hjeWe",
3 => "AAAAA 2023 01 25 04:10:13 ID:13454B43A",
4 => "BBBBB 2023 01 25 01:44:10 ID:Xj74320fj",
5 => "BBBBB 2023 01 25 07:08:58 ID:13454B43A",
6 => "BBBBB 2023 01 25 08:40:52 ID:Ftzkk800Y",
7 => "BBBBB 2023 01 25 14:10:13 ID:18f5hjeWe"
];
$finalArr = array();
$count_arr = array();
$count_arr1 = array();
foreach($dataArray as $parts){
$lines = explode(' ', $parts);
$finalArr[$lines[0]]['user'][$lines[5]][] = $lines[4];
$count_arr1[$lines[0]]['user'][$lines[5]] = $lines[4];
$count_arr[$lines[0]][] = 1;
}
foreach($finalArr as $key => $parts){
$finalArr[$key]['first'] = reset($count_arr1[$key]['user']);
$finalArr[$key]['last'] = end($count_arr1[$key]['user']);
$finalArr[$key]['totaUser'] = count($finalArr[$key]['user']);
$finalArr[$key]['totalAccess'] = count($count_arr[$key]);
}
print_r($finalArr);

how to compare 2 array and compare difference of same id in php?

this questin is asked many times but every one using same array but in my case i have 2 arrays
consider i have 2 arrays
array1:3 [
10 => 900.0
20 => 450.0
30 => 600.0
]
array2:3 [
30 => 200.0
10 => 500.0
20 => 600.0
]
output should be
[900.0 - 500 = 400 // according to same id 10 = 10
450.0 - 600 = -150 // 20 = 20
600.0 - 200 = 400 // 30 = 30
]
in this array consider 10,20,30 are ids and next is value i want output where compare ever id and get difference example if (id1 = id2 ){ id1 => value - id2 => value }
i need help in that code which i already tried
$getsellerreport = SellerSellsReport::where('seller_id' , $seller_id);
$getunitdiff = $getsellerreport->pluck('unit')->toArray();// [0 => 75 1 => 500 => 100]
$getamountdiff = $getsellerreport->pluck('amount')->toArray(); // [0 => 11000 => 40 2 => 900]
$getproductdiff = $getsellerreport->pluck('product_id')->toArray(); // [0 => 39 1 => 242 => 23]
foreach($product_report as $preport){
$unit[] = $preport['unit'];// [0 => 75 1 => 25 2 => 100]
$amount[] = $preport['amount'];// [0 => 900 1 => 450 2 => 600]
$product_id[] = $preport['product_id'];// [0 => 23 1 => 242 => 39]
} // here we get array two values
above code get values with starting 0 key value and on below for() loop we can use product_id to compare both product id and get unit and amount but i dont know how i can do that can someone help me?
for ($i = 0 ; $i < sizeof($amount) ; $i++){
$unitdiff[] = $getunitdiff[$i] - $unit[$i];
$amountdiff[] = $getamountdiff[$i] - $amount[$i];
}
You could collect the arrays and use map, here is a sample to get you started:
$a = [
10 => 900.0,
20 => 450.0,
30 => 600.0,
];
$b = [
30 => 200.0,
10 => 500.0,
20 => 600.0,
];
$x = collect($a)->map(function($aItem, $index) use ($b) {
return $aItem - $b[$index];
});
dd($x); // yields [ 10 => 400.0, 20 => -150.0, 30 => 400.0 ]

I want to remove the common elements in two arrays using PHP [duplicate]

This question already has answers here:
How to remove an array value from another array using PHP question
(3 answers)
Closed 2 years ago.
I tried the following code and it should be working, but not getting the required result. What's wrong with the code? I have two arrays and I want to remove the common elements in both arrays so I wore the following code.
<?php
$aMgaMembersList= array (
0 => '9194962',
1 => '9197448',
2 => '9174039',
3 => '9199473',
4 => '9175598',
5 => '9197474',
6 => '9195444',
7 => '9195268',
8 => '9189438',
9 => '9175103',
10 => '9199619',
11 => '9195267',
12 => '9194463',
13 => '9196333',
14 => '9197471',
15 => '9198479',
16 => '9197472',
17 => '9185479',
18 => '9197452',
19 => '9197442',
20 => '9180861',
21 => '9194950',
22 => '9198464',
23 => '9199613',
24 => '9175939',
25 => '9195442',
26 => '9190203',
27 => '9199613',
) ;
$aRocketMembersList = array (
0 => '9174039',
1 => '9175103',
2 => '9175598',
3 => '9175939',
4 => '9180861',
5 => '9185479',
6 => '9189438',
7 => '9190203',
8 => '9194463',
9 => '9194950',
10 => '9194962',
11 => '9195267',
12 => '9195268',
13 => '9195442',
14 => '9195444',
15 => '9196333',
16 => '9197442',
17 => '9197448',
18 => '9197452',
19 => '9197471',
20 => '9197472',
21 => '9197474',
22 => '9198464',
23 => '9198479',
24 => '9199473',
25 => '9199613',
26 => '9199619',
27 => 'arun',
) ;
if (is_array($aRocketMembersList)) {
foreach ($aRocketMembersList as $rocketUsername) {
if (in_array($rocketUsername, $aMgaMembersList)) {
unset($aMgaMembersList[array_search($rocketUsername, $aMgaMembersList)]);
unset($aRocketMembersList[array_search($rocketUsername, $aRocketMembersList)]);
}
}
}
print_r($aRocketMembersList);
print_r($aMgaMembersList);
The out put is
Array
(
[27] => arun
)
Array
(
[27] => 9199613
)
The element 9199613 shouldn't be there. Why it's happening? I ran the code in a different environment and the result is same.
Here's a different function that works regardless of the order of Arrays:
<?php
function different($array1, $array2){
$m = array_merge($array1, $array2); $x = array_intersect($array1, $array2); $a = array_diff($m, $x); $b = array_diff($x, $m); $a = array_merge($a, $b);
$r = [];
foreach($a as $v){
$o = new StdClass; $k = array_search($v, $array1);
if($k === false)$k = array_search($v, $array2);
$o->$k = [$array1[$k], $array2[$k]]; $r[] = $o;
}
return $r;
}
$aMgaMembersList = [
0 => '9194962',
1 => '9197448',
2 => '9174039',
3 => '9199473',
4 => '9175598',
5 => '9197474',
6 => '9195444',
7 => '9195268',
8 => '9189438',
9 => '9175103',
10 => '9199619',
11 => '9195267',
12 => '9194463',
13 => '9196333',
14 => '9197471',
15 => '9198479',
16 => '9197472',
17 => '9185479',
18 => '9197452',
19 => '9197442',
20 => '9180861',
21 => '9194950',
22 => '9198464',
23 => '9199613',
24 => '9175939',
25 => '9195442',
26 => '9190203',
27 => '9199613'
];
$aRocketMembersList = [
0 => '9174039',
1 => '9175103',
2 => '9175598',
3 => '9175939',
4 => '9180861',
5 => '9185479',
6 => '9189438',
7 => '9190203',
8 => '9194463',
9 => '9194950',
10 => '9194962',
11 => '9195267',
12 => '9195268',
13 => '9195442',
14 => '9195444',
15 => '9196333',
16 => '9197442',
17 => '9197448',
18 => '9197452',
19 => '9197471',
20 => '9197472',
21 => '9197474',
22 => '9198464',
23 => '9198479',
24 => '9199473',
25 => '9199613',
26 => '9199619',
27 => 'arun'
];
$diffArray = different($aMgaMembersList, $aRocketMembersList);
$test = json_encode($diffArray);
?>
$tmp1 = array_diff($aMgaMembersList,$aRocketMembersList);
$tmp2 = array_diff($aRocketMembersList,$aMgaMembersList);
$final = array_unqiue(array_merge($tmp1, $tmp2));
unset($tmp1);unset($tmp2);//and maybe original arrays?
There are probably better solutions, but that should work for you. If you had associative arrays instead of numeric values you could exclude array_unqiue
EDIT:
I originally assumed you wanted the results in one array, if that's unnecessary just use the array_diff function twice, and you can maintain your original array names as desired. Again there are probably better solutions (more memory/processor efficient), but in most practical cases this will be fine. If you're working with extremely large data sets... do more research ;)

How to Create complex Array Structure in PHP

I have to make this kind of structure in array;
We have three ( 3 ) variables which creates this structure:
$numberOfParticipants = 38; // 38 is example
$numberOfParticipantsPerHeat = 8 // 8 is example
$numberOfHeats = 5; // 5 is example
Based on this variables I have this table:
The problem is that, I can't place the ' - ' or null after 31 OR 38. The task is that i have to make the arrays of array "almost equal" like the photo and must depend on the variables above. By the way, after I create the correct list I will slice the array to 5 or 6 or whatever parts I need this is not the problem, the problem is that I have to parse the list like this first. This is what I tried so far:
$calc1 = (int)round($numberOfParticipants * $numberOfParticipantsPerHeat, -1); //First round the numberOfParticipants to closest integer by 10
$readyArr = [];
for ($i = 1; $i <= $calc1; $i++) {
if ($i <= $numberOfParticipants) {
$readyArr[$i] = $i;
} else {
$readyArr[$i] = null;
}
}
The problem with this snippet is that it places the null at the end of the list not after 31, or based on the var.
This is the result I have:
array:40 [▼
1 => 1
2 => 2
3 => 3
4 => 4
5 => 5
6 => 6
7 => 7
8 => 8
9 => 9
10 => 10
11 => 11
12 => 12
13 => 13
14 => 14
15 => 15
16 => 16
17 => 17
18 => 18
19 => 19
20 => 20
21 => 21
22 => 22
23 => 23
24 => 24
25 => 25
26 => 26
27 => 27
28 => 28
29 => 29
30 => 30
31 => 31
32 => 32
33 => 33
34 => 34
35 => 35
36 => 36
37 => 37
38 => 38
39 => null
40 => null
]
The Array after partition I want should be:
array(
0 => array(0 => 1, 1 => 2, 2 => 3, 3 => 4, 4 => 5, 5 => 6, 6 => 7, 7 => 8,),
1 => array(0 => 9, 1 => 10, 2 => 11, 3 => 12, 4 => 13, 5 => 14, 6 => 15, 7 => 16,),
2 => array(0 => 17, 1 => 18, 2 => 19, 3 => 20, 4 => 21, 5 => 22, 6 => 23, 7 => 24,),
3 => array(0 => 25, 1 => 26, 2 => 27, 3 => 28, 4 => 29, 5 => 30, 6 => 31, 7 => null,),
4 => array(0 => 32, 1 => 33, 2 => 34, 3 => 35, 4 => 36, 5 => 37, 6 => 38, 7 => null,),
);
Every help, every clue will be highly appreciated.
There are two things you need to know about the target structure:
How many players are in the first (which will always be the largest, if only by one) set.
$playersPerHeat = ceil($numberOfParticipants / $numberOfHeats);
// note this replaces your hard-coded $numberOfParticipantsPerHeat
You also need to know how many heats actually have that many, that is how many heats are actually full.
$fullHeats = $numberOfParticipants % $numberOfHeats ?: $numberOfHeats;
// The ?: bit means that if we get zero (ie. all equal heats), then we
// count all the heats instead, since they're all full.
Now it's easy!
$players = range(1,$numberOfParticipants);
$heats = array_merge(
array_chunk(
array_slice($players, 0, $fullHeats * $playersPerHeat),
$playersPerHeat
),
array_chunk(
array_slice($players, $fullHeats * $playersPerHeat),
$playersPerHeat - 1
)
);
That's it! Demo

Total for columns in a table

I want to calculate the totals for a series of columns in a table, how do I go about doing this?
Here is a sample of the data I want to sum:
array:1 [
"traders" => array:6 [
"Jim Mayor__targeted_target" => array:2 [
"amounts" => array:13 [
0 => 5
1 => 5
2 => 0
3 => 0
4 => 0
5 => 0
6 => 0
7 => 0
8 => 0
9 => 0
10 => 0
11 => 0
]
"row_name" => "Targeted target"
]
"Jim Mayor__actual_targeted" => array:2 [
"amounts" => array:13 [
0 => 0
1 => 1
2 => 0
3 => 0
4 => 0
5 => 0
6 => 1
7 => 1
8 => 0
9 => 0
10 => 0
11 => 0
]
"row_name" => "Actual targeted"
]
"Bob Martinez__targeted_target" => array:2 [
"amounts" => array:13 [
0 => 1
1 => 0
2 => 0
3 => 0
4 => 0
5 => 0
6 => 0
7 => 0
8 => 0
9 => 0
10 => 0
11 => 0
]
"row_name" => "Targeted target"
]
"Bob Martinez__actual_targeted" => array:2 [
"amounts" => array:13 [
0 => 19
1 => 45
2 => 20
3 => 26
4 => 21
5 => 10
6 => 12
7 => 20
8 => 11
9 => 2
10 => 0
11 => 0
]
"row_name" => "Actual targeted"
]
...
I want to sum together each index, e.g. for Jim Mayor__targeted_target, index 0 added to index 0 of Bob Martinez__targeted_target (this gives the total for January). It needs to work with an unlimited number of traders.
The function that generates the data:
protected function addRow($func, $params, $data, $year, $traderName, $rowName, $type, $image = null, $format = null, $underline = false)
{
$date = Carbon::createFromDate($year, 4, 1);
$total = 0;
$traderName = $traderName . '__' . str_replace(' ', '_', strtolower($rowName));
for ($i = 1; $i < 13; $i++) {
$params[1] = $date->year;
$params[2] = $date->month;
$result = call_user_func_array($func, $params);
$data['traders'][$traderName]['amounts'][] = $result ? $result : 0;
$total += $result;
$date->addMonth();
}
$data['traders'][$traderName]['amounts'][] = $total;
$data['traders'][$traderName]['row_name'] = $rowName;
return $data;
}
Just go over your data and save results in an additional array:
$results = array();
foreach ($traders as $trader) {
foreach ($trader['amounts'] as $i => $amount) {
if (!isset($results[$i])) {
$results[$i] = 0;
}
$results[$i] += $amount;
}
}
The result array will contains the sums of all traders.
Not tested but should work.
Do something like this:
function sumRowsByMonth($traders)
{
$sums = array_fill(0, 12, 0);
foreach($traders as $trader) {
foreach($trader['amounts'] as $monthId => $amount) {
$sums[$monthId] += $amount;
}
}
return $sums;
}
I tested with this:
$arr = array(
'traders' => array(
'Jim Mayor__targeted_target' => array(
'amounts' => array(
0 => 5,
1 => 5,
2 => 0,
3 => 0,
4 => 0,
5 => 0,
6 => 0,
7 => 0,
8 => 0,
9 => 0,
10 => 0,
11 => 0,
)
),
'Bob Martinez__targeted_target' => array(
'amounts' => array(
0 => 19,
1 => 45,
2 => 20,
3 => 26,
4 => 21,
5 => 10,
6 => 12,
7 => 20,
8 => 11,
9 => 2,
10 => 0,
11 => 0,
)
),
),
);
var_dump(sumRowsByMonth($arr['traders']));
Use array_sum() function.
array_sum() returns the sum of values in an array
Also, you said you want to count targeted target and actual targeted separately.
$actual = [];
$targeted = [];
foreach ($traders as $trader) {
$sum = array_sum($trader['anmounts']);
$trader['row_name'] === 'Actual targeted') ? $actual += $sum : $target += $sum;
}
Maybe you'll need to modify this a little bit to tune behavior, but I guess I got the idea.
#imperium2335:
The main problem I keep getting that it is summing all rows, including actual_targeted. actual_targeted needs to be grouped and summed separately to targeted_target.
Then do this:
function sumRowsByMonth($traders)
{
$sums = array();
foreach($traders as $traderName => $trader) {
$type = strstr($traderName, '__');
if( empty($sums[$type]) ) {
$sums[$type] = array_fill(0, 12, 0);
}
foreach($trader['amounts'] as $monthId => $amount) {
$sums[$type][$monthId] += $amount;
}
}
return $sums;
}
Read this:
http://php.net/manual/en/function.strstr.php

Categories