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

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
}
}
}

Related

PHP sort multidimensional array by array list priority [duplicate]

This question already has answers here:
Sorting a php array of arrays by custom order
(8 answers)
Closed 28 days ago.
I have array $data containing data about animals. I would like to sort this array by child element:
source array ($data):
Array (
[0] => (
'name' => 'Leo'
'type' => 'cat'
)
[1] => (
'name' => 'Max'
'type' => 'dog'
)
[2] => (
'name' => 'Elsa'
'type' => 'fish'
)
...
)
priority array ($priority)
$priority = [
'fish', 'dog', 'cat',
];
I would like to sort source array using priority array. I tried:
sort($data, function (int $item1, int $item2) use($priority) {
foreach($priority as $key => $value) {
if($item1 == $value)
{
return 0;
break;
}
if($item2 == $value)
{
return 1;
break;
}
}
return 0;
});
You can use usort with a custom compare function, like so:
<?php
$arr = array(
0 => array(
'name' => 'Leo',
'type' => 'cat'
),
1 => array(
'name' => 'Max',
'type' => 'dog'
),
2 => array(
'name' => 'Elsa',
'type' => 'fish'
)
);
$priority = array('fish', 'dog', 'cat');
usort($arr, function($a, $b) use($priority) {
return array_search($a['type'], $priority) <=> array_search($b['type'], $priority);
});
var_dump($arr);
How this works:
usort accepts a custom compare function, you can pass it the priority array, then use the spaceship operator to compare the value indexes in priority.
Try it out: http://sandbox.onlinephpfunctions.com/code/03fdfa61b1bd8b0b84e5f08ab11b6bc90eeaef4a

PHP array_filter on array containing multiple arrays

I'm using array_filter in PHP to split an array containing multiple arrays when the value of a key named type matches a specific string. Here's what this looks like:
Sample Array
$arr[] = Array (
[0] => Array ( [type] => Recurring ... )
[1] => Array ( [type] => Single ... )
)
Functions
function recurring($value)
{
return ($value['type'] == 'Recurring');
}
function single($value)
{
return ($value['type'] == 'Single');
}
Split Arrays
$recurring = array_filter($arr, 'recurring');
$single = array_filter($arr, 'single');
This works, but I was curious if there was a way to simplify it so that I could create additional filtered arrays in the future without creating a new function for each.
I've started setting up a single function using a closure, but I'm not sure how to do it. Any ideas?
function key_type($value, $key, $string) {
return $key == 'type' && $value == $string;
}
$recurring = array_filter($arr,
key_type('Recurring'), ARRAY_FILTER_USE_BOTH);
$single = array_filter($pricing,
key_type('Single'), ARRAY_FILTER_USE_BOTH);
You could actually do what you proposed in your question. You just need to have the key_type() function return a callable function, which is what array_filter expects as the second parameter. You can return an anonymous function and pass the argument into the anonymous function using the use keyword as CBroe mentioned in the comments.
Here is an example:
function key_type($key) {
return function($value) use ($key) {
return $value['type'] == $key;
};
}
$arr = array(
array('type'=>'Recurring'),
array('type'=>'Single')
);
print_r(array_filter($arr, key_type('Single'), ARRAY_FILTER_USE_BOTH));
The above code will output:
Array ( [1] => Array ( [type] => Single ) )
The beauty of this method is that if you need to change the logic for all instances where you need to use your filter, you just have to change it one time in your key_type function.
An approach would be like below, however I don't like it honestly.
$array = [['type' => 'Single'], ['type' => 'Recurring']];
function key_type($value) {
global $string;
return $value['type'] == $string;
}
($string = 'Recurring') && ($recurring = array_filter($array, 'key_type'));
($string = 'Single') && ($single = array_filter($array, 'key_type'));
Another way to achieve same thing is using Anonymous functions (closures). Don't think much about being DRY it seems nice:
$array = [['type' => 'Single'], ['type' => 'Recurring']];
$recurring = array_filter($array, function($value) {
return $value['type'] == 'Recurring';
});
$single = array_filter($array, function($value) {
return $value['type'] == 'Single';
});
This task might be more about grouping than filtering -- it is difficult to discern from the limited sample data.
As a general rule, I strongly advise against using variable variables in PHP code. It is better practice to store data in arrays for accessibility reasons.
If you only have the two mentioned type values in your project data, then the conditional can be removed entirely.
Code: (Demo)
$array = [
['type' => 'Recurring', 'id' => 1],
['type' => 'Single', 'id' => 2],
['type' => 'Other', 'id' => 3],
['type' => 'Recurring', 'id' => 4],
['type' => 'Single', 'id' => 5],
];
$result = [];
foreach ($array as $row) {
if (in_array($row['type'], ['Recurring', 'Single'])) {
$result[strtolower($row['type'])][] = $row;
}
}
var_export($result);
Output:
array (
'recurring' =>
array (
0 =>
array (
'type' => 'Recurring',
'id' => 1,
),
1 =>
array (
'type' => 'Recurring',
'id' => 4,
),
),
'single' =>
array (
0 =>
array (
'type' => 'Single',
'id' => 2,
),
1 =>
array (
'type' => 'Single',
'id' => 5,
),
),
)

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;
}, []);

Get path and value of all elements in nested associative array

Consider an associative array of arbitrary form and nesting depth, for example:
$someVar = array(
'name' => 'Dotan',
'age' => 35,
'children' => array(
0 => array(
'name' => 'Meirav',
'age' => 6,
),
1 => array(
'name' => 'Maayan',
'age' => 4,
)
),
'dogs' => array('Gili', 'Gipsy')
);
I would like to convert this to an associative array of paths and values:
$someVar = array(
'name' => 'Dotan',
'age' => 35,
'children/0/name' => 'Meirav',
'children/0/age' => 6,
'children/1/name' => 'Maayan',
'children/1/age' => 4,
'dogs/0' => 'Gili',
'dogs/1' => 'Gipsy'
);
I began writing a recursive function which for array elements would recurse and for non-array elements (int, floats, bools, and strings) return an array $return['path'] and $return['value']. This got sloppy quick! Is there a better way to do this in PHP? I would assume that callables and objects would not be passed in the array, though any solution which deals with that possibility would be best. Also, I am assuming that the input array would not have the / character in an element name, but accounting for that might be prudent! Note that the input array could be nested as deep as 8 or more levels deep!
Recursion is really the only way you'll be able to handle this, but here's a simple version to start with:
function nested_values($array, $path=""){
$output = array();
foreach($array as $key => $value) {
if(is_array($value)) {
$output = array_merge($output, nested_values($value, (!empty($path)) ? $path.$key."/" : $key."/"));
}
else $output[$path.$key] = $value;
}
return $output;
}
function getRecursive($path, $node) {
if (is_array($node)) {
$ret = '';
foreach($node as $key => $val)
$ret .= getRecursive($path.'.'.$key, $val);
return $ret;
}
return $path.' => '.$node."\n";
}
$r = getRecursive('', $someVar);
print_r($r);
All yours to place it in an array.

PHP: find key position in multidimensional array [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
PHP: get keys of independent arrays
Hello.
I have a multi-dimensional array. I want a function that finds the position of the given array key (all my array keys are strings) and then returns the position of the key as an array.
E.g:
$arr = array
(
'fruit' => array(
'apples' => array(),
'oranges' => array(),
'bananas' => array()
),
'vegetables' => array(
'tomatoes' => array(),
'carrots' => array(),
'celery' => array(),
'beets' => array
(
'bears' => array(),
'battlestar-galactica' => array()
),
),
'meat' => array(),
'other' => array()
);
Now if I call the function like this:
theFunction('bears');
It should return:
array(1, 3, 0);
function array_tree_search_key($a, $subkey) {
foreach (array_keys($a) as $i=>$k) {
if ($k == $subkey) {
return array($i);
}
elseif ($pos = array_tree_search_key($a[$k], $subkey)) {
return array_merge(array($i), $pos);
}
}
}

Categories