php compare multidimensional array - php

I'm having problems comparing these arrays.
In a nutshell I want to check if $tid_and_date_arr exists within $curr_vals. (Have a look. It does, obviously.)
My logic is flawed, however, as the second time during the loop, $tid_and_date_arr != $value[1] so the value isn't skipped.
What am I missing? Another loop inside the loop?
$curr_vals = array(array('tid' => 22, 'date' => 1497250800), array('tid' => 22, 'date' => 1497337200));
$tid_and_date_arr = array('tid' => 22, 'date' => 1497250800));
foreach($curr_vals as $value){
if ($tid_and_date_arr == $value) {
// skip these values as we've already saved them
continue;
}
else {
// save these values as they are new
}
}

What is wrong with good old array_search?
$curr_vals = array(array('tid' => 22, 'date' => 1497250800), array('tid' => 22, 'date' => 1497337200));
//$tid_and_date_arr = array('tid' => 22, 'date' => 1497250800); -- this will output 0
$tid_and_date_arr = array('tid' => 22, 'date' => 1497337200);
$result = array_search($tid_and_date_arr, $curr_vals);
print_r($result);
This will output the key of the subarray you're looking for:
1

Related

sorting a multi dimensional array in php

I have an array of arrays, as such
$statuses = array(
[0] => array('id'=>10, 'status' => 'active'),
[1] => array('id'=>11, 'status' => 'closed'),
[2] => array('id'=>12, 'status' => 'active'),
[3] => array('id'=>13, 'status' => 'stopped'),
)
I want to be able to make a new array of arrays and each of those sub arrays would contain the elements based on if they had the same status.
The trick here is, I do not want to do a case check based on hard coded status names as they can be random. I want to basically do a dynamic comparison, and say "if you are unique, then create a new array and stick yourself in there, if an array already exists with the same status than stick me in there instead". A sample result could look something like this.
Ive really had a challenge with this because the only way I can think to do it is check every single element against every other single element, and if unique than create a new array. This gets out of control fast if the original array is larger than 100. There must be some built in functions that can make this efficient.
<?php
$sortedArray = array(
['active'] => array(
array(
'id' => 10,
'status' => 'active'
),
array(
'id' => 12,
'status' => 'active'
)
),
['closed'] => array(
array(
'id' => 11,
'status' => 'active'
)
),
['stopped'] => array(
array(
'id' => 13,
'status' => 'active'
)
),
)
$SortedArray = array();
$SortedArray['active'] = array();
$SortedArray['closed'] = array();
$SortedArray['stopped'] = array();
foreach($statuses as $Curr) {
if ($Curr['status'] == 'active') { $SortedArray['active'][] = $Curr; }
if ($Curr['status'] == 'closed') { $SortedArray['closed'][] = $Curr; }
if ($Curr['status'] == 'stopped') { $SortedArray['stopped'][] = $Curr; }
}
You can also do it with functional way though it's pretty the same like Marc said.
$sorted = array_reduce($statuses, function($carry, $status) {
$carry[$status['status']][] = $status;
return $carry;
}, []);

PHP arrays: summing values with matching dates

i'm trying to figure out how to sum certain values of a multi-dimensional array if they have similar dates.
Here's my array:
<?$myArray=array(
array(
'year' => 2011,
'month ' => 5,
'day' => 13,
'value' => 2
),
array(
'year' => 2011,
'month '=> 5,
'day' => 14,
'value' => 5
),
array(
'year' => 2011,
'month ' => 5,
'day' => 13,
'value' => 1
),
array(
'year' => 2011,
'month ' => 5,
'day' => 14,
'value' => 9
)
);?>
here's how i'd like the output to look:
<?$output=array(
array(
'year' => 2011,
'month ' => 5,
'day' => 13,
'value' => 3 //the sum of 1+2
),
array(
'year' => 2011,
'month '=> 5,
'day' => 14,
'value' => 14 //the sum of 5+9
)
);?>
Notice how the 4 sub-arrays were matched on year/month/day and then only the value was summed. I've seen other SO threads on this topic but can't find one where only the value is summed and not the year/month/day values too.
Thoughts?
It may be easiest to initially index your output array with a combination of the year/month/day:
Note: Your example array above has all its month keys with a trailing space. I'm just using month here with no trailing space.
// Initialize output array...
$out = array();
// Looping over each input array item
foreach ($myArray as $elem) {
// Initialize a new element in the output keyed as yyyy-mm-dd if it doesn't already exist
if (!isset($out[$elem['year'] . "-" . $elem['month '] . "-" . $elem['day']])) {
$out[$elem['year'] . "-" . $elem['month '] . "-" . $elem['day']] = array(
// Set the date keys...
'year' => $elem['year'],
'month' => $elem['month '],
'day' => $elem['day'],
// With the current value...
'value' => $elem['value']
);
}
// If it already exists, just add the current value onto it...
else {
$out[$elem['year'] . "-" . $elem['month '] . "-" . $elem['day']]['value'] += $elem['value'];
}
}
// Now your output array is keyed by date. Use array_values() to strip off those keys if it matters:
$out = array_values($out);
Outputs (before calling array_values()):
array(2) {
'2011-5-13' =>
array(4) {
'year' =>
int(2011)
'month' =>
int(5)
'day' =>
int(13)
'value' =>
int(3)
}
'2011-5-14' =>
array(4) {
'year' =>
int(2011)
'month' =>
int(5)
'day' =>
int(14)
'value' =>
int(14)
}
}
Update:
To do the same thing with single-key dates (rather than 3-parts) it is easier without the concatenation:
$myArray=array(
array(
'date' => '2011-05-13',
'value' => 2
),
array(
'date' => '2011-05-14',
'value' => 5
),
array(
'date' => '2011-05-13',
'value' => 7
),
array(
'date' => '2011-05-14',
'value' => 3
),
);
foreach ($myArray as $elem) {
// Initialize a new element in the output if it doesn't already exist
if (!isset($out[$elem['date']])) {
$out[$elem['date'] = array(
// Set the date keys...
'date' => $elem['date'],
// With the current value...
'value' => $elem['value']
);
}
else {
$out[$elem['date']]['value'] += $elem['value'];
}
}
Here's how I would do it. The result will be in $newArray with datetime objects as keys. If you just want it as an indexed array it should be pretty easy to do.
// Example array
$myArray = array(
array(
'date' => new DateTime('1993-08-11'),
'value' => 3
),
array(
'date' => new DateTime('1993-08-11'),
'value' => 5
)
);
$newArray = array();
foreach($myArray as $element)
{
$iterationValue = $element['value'];
$iterationDate = $element['date'];
$dateKey = $iterationDate->format('Y-m-d');
if(array_key_exists($dateKey, $newArray))
{
// If we've already added this date to the new array, add the value
$newArray[$dateKey]['value'] += $iterationValue;
}
else
{
// Otherwise create a new element with datetimeobject as key
$newArray[$dateKey]['date'] = $iterationDate;
$newArray[$dateKey]['value'] = $iterationValue;
}
}
nl2br(print_r($newArray));
Actually ended up doing the pretty much the same thing as #MichaelBerkowski solution. Still, having DateTime objects is always more flexible when you wan't to do things with the dates later in your application.
Edit: Now tested it and fixed errors

Multidimensional array - search for same value

I have a multidimensional array which I am looping through using a foreach loop.
I have then need to check whether any of those arrays have the key of 'parent_page' and the same value of any other arrays, such as:
$arrMulti = array(array(
'page_id' => 1,
'page_parent' => 28,
'page_title' => 'Testing'
), array(
'page_id' => 2,
'page_parent' => 30,
'page_title' => 'A seperate page'
), array(
'page_id' => 3,
'page_parent' => 28,
'page_title' => 'Testing Sub Page'
));
So $arrMulti[0]['page_parent'] would match with $arrMulti[2]['page_parent'], so I need to then create a new array using those, something like this:
$arrParentIDs = array( 'parent_id' => array(
1,
3
));
Sorry for the poor explanation, but do you have any idea on how to do this?
Thanks!
$parentIds = array();
foreach($arrMulti as $temp):
if(isset($temp['page_parent'] && !in_array($temp['page_parent'], $parentIds)){
$parentIds[] = $temp['page_parent'];
}
endforeach;
var_dump($parentIds);//to show the contents
Try something like this..
foreach($arrMulti as $array) {
foreach($array as $key=>$val) {
//your statement/condition
}
}

Check the 'form' of a multidimensional array for validation [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
recursive array_diff()?
I have a static multidimensional array which is always going to be in the same form. E.g. it will have the same keys & hierarchy.
I want to check a posted array to be in the same 'form' as this static array and if not error.
I have been trying various methods but they all seem to end up with a lot of if...else components and are rather messy.
Is there a succinct way to achieve this?
In response to an answer from dfsq:
$etalon = array(
'name' => array(),
'income' => array(
'day' => '',
'month' => array(),
'year' => array()
),
'message' => array(),
);
$test = array(
'name' => array(),
'income' => array(
'day' => '',
'month' => array(),
'year' => array()
),
'message' => array(),
);
// Tests
$diff = array_diff_key_recursive($etalon, $test);
var_dump(empty($diff));
print_r($diff);
And the results from that are
bool(false)
Array ( [name] => 1 [income] => Array ( [month] => 1 [year] => 1 ) [message] => 1 )
Author needs a solution which would test if the structure of the arrays are the same. Next function will make a job.
/**
* $a1 array your static array.
* $a2 array array you want to test.
* #return array difference between arrays. empty result means $a1 and $a2 has the same structure.
*/
function array_diff_key_recursive($a1, $a2)
{
$r = array();
foreach ($a1 as $k => $v)
{
if (is_array($v))
{
if (!isset($a2[$k]) || !is_array($a2[$k]))
{
$r[$k] = $a1[$k];
}
else
{
if ($diff = array_diff_key_recursive($a1[$k], $a2[$k]))
{
$r[$k] = $diff;
}
}
}
else
{
if (!isset($a2[$k]) || is_array($a2[$k]))
{
$r[$k] = $v;
}
}
}
return $r;
}
And test it:
$etalon = array(
'name' => '',
'income' => array(
'day' => '',
'month' => array(),
'year' => array()
),
'message' => ''
);
$test = array(
'name' => 'Tomas Brook',
'income' => array(
'day' => 123,
'month' => 123,
'year' => array()
)
);
// Tests
$diff = array_diff_key_recursive($etalon, $test);
var_dump(empty($diff));
print_r($diff);
This will output:
bool(false)
Array
(
[income] => Array
(
[month] => Array()
)
[message] =>
)
So checking for emptiness of $diff array will tell you if arrays have the same structure.
Note: if you need you can also test it in other direction to see if test array has some extra keys which are not present in original static array.
You could user array_intersect_key() to check if they both contain the same keys. If so, the resulting array from that function will contain the same values as array_keys() on the source array.
AFAIK those functions aren't recursive, so you'd have to write a recursion wrapper around them.
See User-Notes on http://php.net/array_diff_key
Are you searching for the array_diff or array_diff_assoc functions?
use foreach with the ifs...if u have different tests for the different inner keys eg
$many_entries = ("entry1" = array("name"=>"obi", "height"=>10));
and so on, first define functions to check the different keys
then a foreach statement like this
foreach($many_entries as $entry)
{
foreach($entry as $key => $val)
{
switch($key)
{
case "name": //name function
//and so on
}
}
}

How to extract data out of a specific PHP array

I have a multi-dimensional array that looks like this:
The base array is indexed based on category ids from my catalog.
$cat[category_id]
Each base array has three underlying elements:
['parent_id']
['sort_order']
['name']
I want to create a function that allows us to create a list of category_id's and names for a given parent_category_id in the correct sort order. Is this possible? Technically it is the same information, but the array is constructed in a weird way to extract that information.
Here is an example definition for the array:
$cat = array();
$cat[32]['parent_id']= 0;
$cat[32]['sort_order']= 1;
$cat[32]['name']= 'my-category-name1';
$cat[45]['parent_id']= 0;
$cat[45]['sort_order']= 0;
$cat[45]['name']= 'my-category-name2';
$cat[2]['parent_id']= 0;
$cat[2]['sort_order']= 2;
$cat[2]['name'] = "my-category-name3";
$cat[3]['parent_id']= 2;
$cat[3]['sort_order']= 1;
$cat[3]['name'] = "my-category-name4";
$cat[6]['parent_id']= 2;
$cat[6]['sort_order']= 0;
$cat[6]['name'] = "my-category-name5";
Assuming it's something of this sort:
$ary = Array(
0 => Array(
'parent_category_id' => null,
'sort_order' => 0,
'name' => 'my-category-name0'
),
1 => Array(
'parent_category_id' => 0,
'sort_order' => 1,
'name' => 'my-category-name1'
),
2 => Array(
'parent_category_id' => 0,
'sort_order' => 2,
'name' => 'my-category-name2'
),
3 => Array(
'parent_category_id' => null,
'sort_order' => 0,
'name' => 'my-category-name3'
),
4 => Array(
'parent_category_id' => 3,
'sort_order' => 0,
'name' => 'my-category-name4'
)
);
You can use a combination of a foreach and usort to achieve what you're going for.
// #array: the array you're searchign through
// #parent_id: the parent id you're filtering by
function getFromParent($array, $parent_id){
$result = Array();
foreach ($array as $category_id => $entry){
if ($entry['parent_category_id']===$parent_id)
$result[$category_id] = $entry;
}
usort($result,create_function('$a,$b','return ($a["sort_order"]>$b["sort_order"]?1:($b["sort_order"]<$a["sort_order"]?-1:0));'));
return $result;
}
var_export(getFromParent($ary,0));
EDIT Sorry, fixed some syntax errors. Tested, and works (at least to result in what I was intending)
EDITv2 Here's the raw output from the above:
array (
0 =>
array (
'parent_category_id' => 0,
'sort_order' => 1,
'name' => 'my-category-name1',
),
1 =>
array (
'parent_category_id' => 0,
'sort_order' => 2,
'name' => 'my-category-name2',
),
)
(Used var_export just for you #FelixKling)
EDITv3 I've updated my answer to go along with the OP's update. I also now make it retain the original "category_id" values in the result array.
First you create an empty array, it will be used to store your result.
$result = array();
You need to iterate through your initial array, you can use foreach().
Then, given your parent_category_id simply use an if statement to check whether it's the given id or not.
If it is, just construct and push your result to your $result array.
Use any of the sort functions you like
Use the magic return $result;
You're done.
function returnSortedParents($categories, $target_parent){
$new_list = array();
foreach($categories as $index => $array){
//FIND ONLY THE ELEMENTS MATCHING THE TARGET PARENT ID
if($array['parent_category_id']==$target_parent){
$new_list[$index = $array['sort_order'];
}
return asort($new_list); //SORT BASED ON THE VALUES, WHICH IS THE SORTING ORDER
}

Categories