I have following task to do, if there is any chance I would appreciate some help to make it in as efficient way as possible. I need to compare values from array of objects (which comes from Laravel Query Builder join query) with array values.
Objects consist of database stored values:
0 => array:2 [
0 => {#912
+"addition_id": 1
+"valid_from": "2015-09-13 00:00:00"
+"valid_to": "2015-09-19 00:00:00"
+"price": "0.00"
+"mode": 0
+"alias": "Breakfast"
}
1 => {#911
+"addition_id": 2
+"valid_from": "2015-09-13 00:00:00"
+"valid_to": "2015-09-19 00:00:00"
+"price": "10.00"
+"mode": 1
+"alias": "Dinner"
}
while array includes new data, being processed by my method.
0 => array:3 [
0 => array:6 [
"id" => 1
"alias" => "Breakfast"
"price" => "0.00"
"mode" => 0
"created_at" => "2015-09-12 21:25:03"
"updated_at" => "2015-09-12 21:25:03"
]
1 => array:6 [
"id" => 2
"alias" => "Dinner"
"price" => "10.00"
"mode" => 1
"created_at" => "2015-09-12 21:25:18"
"updated_at" => "2015-09-12 21:25:18"
]
2 => array:6 [
"id" => 3
"alias" => "Sauna Access"
"price" => "50.00"
"mode" => 0
"created_at" => "2015-09-12 21:25:35"
"updated_at" => "2015-09-12 21:25:35"
]
]
Now, what I need to do is to find out what position of the array was not in the object (compare id with addition_id) and return it.
Is there any way to do it without two nested foreach loops? I think it can be done somehow smart with array_filter, but I'm not really sure how to write efficient callback (beginner here).
The only way I could get around this was:
private function compareAdditions(array $old,array $new)
{
$difference = $new;
foreach($new as $key => $value) {
foreach($old as $oldEntry) {
if($oldEntry->addition_id == $value['id']) {
unset($difference[$key]);
}
}
}
return $difference;
}
But I would really like to make it without two foreach loops. Help will be very appreciated :)
This might be overkill but it uses a function i write in every project, precisely for these kind of situations :
function additionals($original, $additions) {
$nonExisiting = [];
//convert all the objects in arrays
$additions = json_decode(json_encode($additions), true);
//create an index
$index = hashtable2list($original, 'id');
for(reset($additions); current($additions); next($additions)) {
$pos = array_search(current($additions)['addition_id'], $index);
if($pos !== false) {
//We could replace the originals with the additions in the same loop and save resources
//$original[$pos] = current($additions);
} else {
$nonExisiting[] = current($additions);
}
}
return $nonExisiting;
}
function hashtable2list( $hashtable, $key ){
$array = [];
foreach($hashtable as $entry) {
if( is_array($entry) && isset($entry[$key])) {
$array[] = $entry[$key];
} elseif( is_object($entry) && isset($entry->$key) ) {
$array[] = $entry->$key;
} else {
$array[] = null;
}
}
return $array;
}
Related
I have a problem that has been stressing me out for weeks now and i cannot find a clean solution to it that does not involve recursion.
This is the problem:
Take a flat array of nested associative arrays and group this into one deeply nested object. The top level of this object will have its parent property as null.
This is my solution but i admit it is far from perfect. I am fairly certain this can be done in a single loop without any recursion, but for the life of me i cannot work it out!
//Example single fork
$data = array(
//Top of Tree
0 => array(
"name" => "A",
"parent" => null,
"id" => 1,
),
//B Branch
1 => array(
"name" => "B",
"parent" => "1",
"id" => 2,
),
2 => array(
"name" => "B1",
"parent" => "2",
"id" => 3,
),
3 => array(
"name" => "B2",
"parent" => "3",
"id" => 4,
),
4 => array(
"name" => "B3",
"parent" => "4",
"id" => 5,
),
//C Branch
5 => array(
"name" => "C",
"parent" => "1",
"id" => 6,
),
6 => array(
"name" => "C1",
"parent" => "6",
"id" => 7,
),
7 => array(
"name" => "C2",
"parent" => "7",
"id" => 8,
),
8 => array(
"name" => "C3",
"parent" => "8",
"id" => 9,
),
);
Actual anonymised example
array:7214 [▼
0 => array:3 [▼
"name" => ""
"parent" => null
"id" =>
]
1 => array:3 [▼
"name" => ""
"parent" =>
"id" =>
]
2 => array:3 [▼
"name" => ""
"parent" =>
"id" =>
]
3 => array:3 [▼
"name" => ""
"parent" =>
"id" =>
]
4 => array:3 [▼
"name" => ""
"parent" =>
"id" =>
]
5 => array:3 [▼
"name" => ""
"parent" =>
"id" =>
]
6 => array:3 [▼
"name" => ""
"parent" =>
"id" =>
]
7 => array:3 [▼
"name" => ""
"parent" =>
"id" =>
]
8 => array:3 [▼
"name" => ""
"parent" =>
"id" =>
]
9 => array:3 [▼
"name" => ""
"parent" =>
"id" =>
]
10 => array:3 [▼
"name" => ""
"parent" =>
"id" =>
]
Another example deeper nesting
{
"name":"top",
"id":xxx,
"children":{
"second":{
"name":"second",
"id":xxx,
"children":{
"Third":{
"name":"third",
"id":xxx,
"children":{
"fourth":{
"name":"fourth",
"id":xxx
}
}
}
}
}
}
}
$originalLength = count($data);
$obj = [];
while ($originalLength > 0) {
foreach ($data as $item) {
$name = $item['name'];
$parent = $item['parent'];
$a = isset($obj[$name]) ? $obj[$name] : array('name' => $name, 'id'=>$item['id']);
if (($parent)) {
$path = get_nested_path($parent, $obj, array(['']));
try {
insertItem($obj, $path, $a);
} catch (Exception $e) {
continue;
//echo 'Caught exception: ', $e->getMessage(), "\n";
}
}
$obj[$name] = isset($obj[$name]) ? $obj[$name] : $a;
$originalLength--;
}
}
echo json_encode($obj['A']);
function get_nested_path($parent, $array, $id_path)
{
if (is_array($array) && count($array) > 0) {
foreach ($array as $key => $value) {
$temp_path = $id_path;
array_push($temp_path, $key);
if ($key == "id" && $value == $parent) {
array_shift($temp_path);
array_pop($temp_path);
return $temp_path;
}
if (is_array($value) && count($value) > 0) {
$res_path = get_nested_path(
$parent, $value, $temp_path);
if ($res_path != null) {
return $res_path;
}
}
}
}
return null;
}
function insertItem(&$array, $path, $toInsert)
{
$target = &$array;
foreach ($path as $key) {
if (array_key_exists($key, $target))
$target = &$target[$key];
else throw new Exception('Undefined path: ["' . implode('","', $path) . '"]');
}
$target['children'] = isset($target['children']) ? $target['children'] : [];
$target['children'][$toInsert['name']] = $toInsert;
return $target;
}
Here's my take on what I believe is the desired output:
function buildTree(array $items): ?array {
// Get a mapping of each item by ID, and pre-prepare the "children" property.
$idMap = [];
foreach ($items as $item) {
$idMap[$item['id']] = $item;
$idMap[$item['id']]['children'] = [];
}
// Store a reference to the treetop if we come across it.
$treeTop = null;
// Map items to their parents' children array.
foreach ($idMap as $id => $item) {
if ($item['parent'] && isset($idMap[intval($item['parent'])])) {
$parent = &$idMap[intval($item['parent'])];
$parent['children'][] = &$idMap[$id];
} else if ($item['parent'] === null) {
$treeTop = &$idMap[$id];
}
}
return $treeTop;
}
This does two array cycles, one to map up the data by ID, then one to assign children to parents. Some key elements to note:
The build of $idMap in the first loop also effectively copies the items here so we won't be affecting the original input array (Unless it already contained references).
Within the second loop, there's usage of & to use references to other items, otherwise by default PHP would effectively create a copy upon assignment since these are arrays (And PHP copies arrays on assignment unlike Objects in PHP or arrays in some other languages such as JavaScript). This allows us to effectively share the same array "item" across the structure.
This does not protect against bad input. It's possible that invalid mapping or circular references within the input data could cause problems, although our function should always just be performing two loops, so should at least not get caught in an infinite/exhaustive loop.
I want to merge 2 tables I show you an example:
foreach ($dashboardData as $item) {
$results[$item['month']] = [
DashboardConsts::COLUMN_MONTHLY => $item['month'] ?? null,
DashboardConsts::ROW_NBR => $item['nbr'] ?? null,
DashboardConsts::ROW_SELL_PRICE => $item['sum'] ?? null,
'number' => $item['countNewBc'] ?? null,
];
}
array:2 [▼
"2020-12" => array:4 [▼
"Mois" => "2020-12"
"Nbr vendus" => null
"CA TTC" => null
"number" => "1"
]
"2021-01" => array:4 [▼
"Mois" => "2021-01"
"Nbr vendus" => null
"CA TTC" => null
"number" => "2"
]
]
and
"2020-12" => array:4 [▼
"Mois" => "2020-12"
"Nbr vendus" => "1"
"CA TTC" => "790"
"number" => null
]
"2021-01" => array:4 [▼
"Mois" => "2021-01"
"Nbr vendus" => "3"
"CA TTC" => "1680"
"number" => null
]
Basically here, I make a sort of group my values by period, I try to merge my 2 arrays to ensure that the fields which are 'null'.
I want to replace null values with those that are filled in one of the array.
I had to try to do something like that :
$tableau1 = array_filter($tableau1);
$tableau2 = array_filter($tableau2);
$result = array_merge($tableau1, $tableau2);
but it does not work.
EDIT:
I wish my final result looks like this
array:2 [▼
"2020-12" => array:4 [▼
"Mois" => "2020-12"
"Nbr vendus" => "1"
"CA TTC" => "790"
"number" => "1"
]
"2021-01" => array:4 [▼
"Mois" => "2021-01"
"Nbr vendus" => "3"
"CA TTC" => "1680"
"number" => "2"
]
]
There are many ways of achieving this, all the solutions, needs to go through the arrays, one way or another.
You easily do a foreach () loop marathon and and loads of if () statements to make sure the conversion is correctly made.
Anyways, this is my take on the question.
Remove null values and replace them with array_replace_recursive():
<?php
function array_remove_null($input) {
foreach ($input as &$value) {
if (is_array($value)) {
$value = array_remove_null($value);
}
}
return array_filter($input, function($item){
return $item !== null && $item !== '';
});
}
/**
* Using https://www.php.net/manual/en/function.array-replace-recursive.php
*/
$array1 = [
"2020-12" => [
"Mois" => "2020-12",
"Nbr vendus" => null,
"CA TTC" => null,
"number" => "1",
],
"2021-01" => [
"Mois" => "2021-01",
"Nbr vendus" => null,
"CA TTC" => null,
"number" => "2",
],
];
$array2 = [
"2020-12" => [
"Mois" => "2020-12",
"Nbr vendus" => "1",
"CA TTC" => "790",
"number" => null,
],
"2021-01" => [
"Mois" => "2021-01",
"Nbr vendus" => "3",
"CA TTC" => "1680",
"number" => null,
],
];
$array = array_replace_recursive(array_remove_null($array1), array_remove_null($array2));
var_dump($array);
In action: https://3v4l.org/WJnYu
I think I understand. You need a nested loop to access both sets of data. The following might not be the actual answer, but it's close.
$results = array();
foreach ($inputArrayOne as $onekey => $arrayOne) {
$temp_results = array();
foreach ($inputArrayTwo as $twokey => $arrayTwo) {
if ($onekey != $twokey) {
continue;
}
if (!is_null($arrayOne['month'])) {
$temp_results['Mois'] = $arrayOne['month'];
} else if (!is_null($arrayTwo['month'])) {
$temp_results['Mois'] = $arrayTwo['month'];
} else {
$temp_results['Mois'] = null; // to account for bad data
}
if (!is_null($arrayOne['nbr'])) {
$temp_results['Nbr vendus'] = $arrayOne['nbr'];
} else if (!is_null($arrayTwo['nbr'])) {
$temp_results['Nbr vendus'] = $arrayTwo['nbr'];
} else {
$temp_results['Nbr vendus'] = null; // to account for bad data
}
if (!is_null($arrayOne['sum'])) {
$temp_results['CA TTC'] = $arrayOne['sum'];
} else if (!is_null($arrayTwo['sum'])) {
$temp_results['CA TTC'] = $arrayTwo['sum'];
} else {
$temp_results['CA TTC'] = null; // to account for bad data
}
if (!is_null($arrayOne['countNewBc'])) {
$temp_results['number'] = $arrayOne['countNewBc'];
} else if (!is_null($arrayTwo['countNewBc'])) {
$temp_results['number'] = $arrayTwo['countNewBc'];
} else {
$temp_results['number'] = null; // to account for bad data
}
}
$results[$arrayOne['month']] = $temp_results;
}
I know you got your answer, but if someone stumbles upon this question and don't need recursive (only one level down in array) check then you could do this:
(My logic is simply to replace null with zeros and add together equivalent keys from the arrays. In my code I also take for granted that there are same the same keys in inner array for each array)
$new_arr = array_slice($array1,0);
foreach($array1 as $headkey=>$item) {
foreach($item as $innerkey=>$it) {
$null_change = false;
if ($array1[$headkey][$innerkey] === null) {
$array1[$headkey][$innerkey] == 0;
$null_change = true;
}
if ($array2[$headkey][$innerkey] === null) {
$array2[$headkey][$innerkey] == 0;
$null_change = true;
}
if ($null_change === true) {
$new_arr[$headkey][$innerkey] = $array1[$headkey][$innerkey] +
$array2[$headkey][$innerkey];
}
}
}
var_dump($new_arr);
If you need a more generic result based on unknown number of arrays you could do this (but still only one level in each array):
function replaceNullOccurences(...$arrays) {
if (!is_array($arrays[0])) return;
$new_arr = array_slice($arrays[0],0);
foreach($arrays[0] as $headkey=>$item) {
foreach($item as $innerkey=>$it) {
$null_change = false;
foreach($arrays as $arr) {
if ($arr[$headkey][$innerkey] === null) {
$arr[$headkey][$innerkey] == 0; //Change null to zero for addition below
$null_change = true;
}
}
//If null in the key in any array, sum together the arrays
if ($null_change === true) {
foreach($arrays as $arr) {
$new_arr[$headkey][$innerkey] += $arr[$headkey][$innerkey];
}
}
}
}
return $new_arr;
}
$result = replaceNullOccurences($array1, $array2);
Am working on some set of PHP array. Am trying to loop through each of them and check
the array whose name is equal to Josw Acade. Am using a for loop but I get zero
after extracting the data. I want to store the data in an array.
Array
array:6 [
0 => array:4 [
"id" => 1
"name" => "Josw Acade"
"value" => "Unlimited"
"plan_type" => "Superior"
]
1 => array:4 [
"id" => 2
"name" => "Verbal"
"value" => "true"
"plan_type" => "Superior"
]
2 => array:4 [
"id" => 12
"name" => "Josw Acade"
"value" => "$1,500,00"
"plan_type" => "Classic"
]
3 => array:4 [
"id" => 13
"name" => "Leon"
"value" => "true"
"plan_type" => "Classic"
]
4 => array:4 [
"id" => 14
"name" => "One Time"
"value" => "true"
"plan_type" => "Classic"
]
5 => array:4 [
"id" => 15
"name" => "Deat"
"value" => "$25,000"
"plan_type" => "Classic"
]
6 => array:4 [
"id" => 23
"name" => "Josw Acade"
"value" => "$100,000"
"plan_type" => "Essential"
]
]
Logic
$Inst = [];
for($med = 0; $med < count($array); $med++){
if($med['name'] == "Josw Acade"){
$Inst = $med['value'];
}
}
dd($Inst);
Your variables is not corretly set in the for loop, you are setting $med = 0 and acessing $med as an array.
Use filter, that runs a condition on each element and returns the items that satisfy that condition.
array_filter($array, function ($item) {
return $item['name'] === 'Josw Acade';
});
In general you don't have to make old school arrays anymore, foreach does the same.
$results = [];
foreach($array as $item)
{
if ($item['name'] === 'Josw Acade') {
$results[] = $item['value'];
}
}
You can use array_filter with callback
$filtered = array_filter($array, function($v){ return $v['name'] == 'Josw Acade'})
print_r($filtered);
You are looping through array; so on each iteration to get values; you need to pass index value and you are missing that. You are using $med as index.
Here is code.
$Inst = [];
for($med = 0; $med < count($array); $med++){
if($array[$med]['name'] == "Josw Acade"){
$Inst[] = $array[$med]['value'];
}
}
there is many way to do this but according to me the best way to use array_filer()
array_filter($array, function ($item) {
return $item['name'] === 'Josw Acade';
});
To put it right lets say I have an array stores-
array:3 [▼
0 => "store3"
1 => "store"
2 => "store2"
]
This is the array which holds values.
Other array products holds all the data:-
array:2 [▼
0 => array:2 [▼
"store" => "store"
"product" => "1"
]
1 => array:2 [▼
"store" => "store"
"product" => "4"
]
2 => array:2 [▼
"store" => "store2"
"product" => "2"
]
3 => array:2 [▼
"store" => "store2"
"product" => "3"
]
4 => array:2 [▼
"store" => "store3"
"product" => "7"
]
5 => array:2 [▼
"store" => "store3"
"product" => "11"
]
]
What I want is that a value is picked from stores array eg store3 then it is compared with products array and being searched and extract all the arrays inside products array which has the store value store3 and store it in another new array named store3
I have tried to do it but it was very wrong I mean it didn't work! I will post it if anyone say so but can anyone accomplish this?
My work:-
$temp = array();
for($i=0; $i<count($stores); $i++)
{
//$stores[$i] = array();
foreach($products as $p)
{
if(session($stores[$i]) == $p['store'])
{
if(count(session($stores[$i])) == 0)
{
$temp['product'] = $p['product'];
session($stores[$i])->push($temp['product']);
}
else if(!in_array($p['product'],$stores[$i]))
{
$temp['product'] = $p['product'];
session($stores[$i])->push($temp['product']);
}
}
}
}
Do it like below:-
$final_array = array();
foreach($array1 as $arr){
foreach($array2 as $arr2){
if($arr == $arr2['store']){
$final_array[$arr]['product'][] = $arr2['product'];
}
}
}
echo "<pre/>";print_r($final_array);
Output:-https://eval.in/752498
using array_walk
$array = [];
array_walk($products, function ($value, $key) use ($stores, &$array) {
$array[$value['store']][] = $value['product'];
});
live sample : https://3v4l.org/BfeMm
using array filter
$store = 'store1';
$products = array_filter($products, function($product) use($store) {
return (isset($product['store']) and $product['store'] == $store);
});
var_dump($products);
https://eval.in/752508
I made a simple function to find products in store
function searchProduct($products,$storeName){
$results =array();
foreach($products as $product){
if(in_array($storeName,array_values($product)))
$results[] = $product;
}
return $results;
}
print_r(searchProduct($products,'store3'));
I have an array of arrays carrying data of multiple forms
i wanna split each form's data into a single array so i can store it to DB
currently doing
public function storeWBS(Request $request)
{
$value = $request->all();
$formValue = new WorkBreakdownStructure;
$count = 0;
$data_array1 = array();
foreach ($value as $key => $val2) {
$data_array= $val2;
if (is_array($val2)) {
array_push($data_array1, $val2);
}
}
dd($value);
exit;
$data_array1->save();
}
and Getting this result
array:4 [▼
"_token" => "bcK0e9z168ib7rbSZpoRPLWbhx3bRIHq1NqzfNeX"
"idea_id" => array:3 [▼
0 => "1"
1 => "1"
2 => "1"
]
"wbs_description" => array:3 [▼
0 => "Visit Campus to read about making great videos and more"
1 => "Visit Campus to read about \r\n"
2 => "Visit Campus to read about making great"
]
"percentage" => array:3 [▼
0 => "30"
1 => "30"
2 => "40"
]
]
i want the to get all values of inner array's index 0 to be in one array
i.e,
"idea_id"
=> "1"
"wbs_description"
=> "Visit Campus to read about making great videos and more"
"percentage"
=> "30"
from above i tried to run an inner loop but it'll result with same 3 arrays
foreach ($arr as $key => $val2) {
$data_array= $val2;
if (is_array($val2)) {
$count = 0;
foreach ($val2 as $k=>$v) {
$data_array1[$count][$key] = $v;
$count++;
}
}
}