This question already has answers here:
Get difference between associative rows of two 2-dimensional arrays
(5 answers)
Closed last year.
It seems that every PHP function I read about for comparing arrays (array_diff(), array_intersect(), etc) compares for the existence of array elements.
Given two multidimensional arrays with identical structure, how would you list the differences in values?
Example
Array 1
[User1] => Array ([public] => 1
[private] => 1
[secret] => 1
)
[User2] => Array ([public] => 1
[private] => 0
[secret] => 0
)
Array 2
[User1] => Array ([public] => 1
[private] => 0
[secret] => 1
)
[User2] => Array ([public] => 1
[private] => 0
[secret] => 0
)
Difference
[User1] => Array ([public] => 1
[private] => 0 //this value is different
[secret] => 1
)
So my result would be - "Of all the users, User1 has changed, and the difference is that private is 0 instead of 1."
One way is to write a function to do something similar to this..
function compareArray ($array1, $array2)
{
foreach ($array1 as $key => $value)
{
if ($array2[$key] != $value)
{
return false;
}
}
return true;
}
You could easily augment that function to return an array of differences in the two..
Edit - Here's a refined version that more closely resembles what you're looking for:
function compareArray ($array1, $array2)
{
var $differences;
foreach ($array1 as $key => $value)
{
if ($array2[$key] != $value)
{
$differences[$key][1] = $value;
$differences[$key][2] = $array2[$key];
}
}
if (sizeof($differences) > 0)
{
return $differences;
}
else
{
return true;
}
}
I think this does what you're looking for.
Using your sample data, doing a loop on the outer arrays, then using array_diff_assoc on the users each time through. (Note, this assumes that when there's a difference, array_diff_assoc returns the value from the second array passed in, which it seems to do).
<?php
$user1 = array("public" => 1, "private" => 1, "secret" => 1);
$user2 = array("public" => 1, "private" =>1, "secret" => 1);
$array1 = array ("user 1"=>$user1, "user 2"=>$user2);
$user1 = array("public" => 1, "private" => 0, "secret" => 1);
$user2 = array("public" => 1, "private" => 1, "secret" => 1);
$array2 = array("user 1"=>$user1, "user 2"=>$user2);
$results = array();
foreach ( $array1 as $user => $value )
{
$diff = array_diff_assoc( $array1[$user], $array2[$user] );
if ($diff) {
array_push($results,array($user=>$diff));
}
}
print_r($results);
?>
It returns:
Array
(
[0] => Array
(
[user 1] => Array
(
[private] => 1
)
)
)
Try this function:
function arrayDiff($array1, $array2)
{
if (!is_array($array1) || !is_array($array2)) {
return false;
}
foreach ($array1 as $key => $val) {
if (array_key_exists($key, $array2) && gettype($val) != "array" && $val === $array2[$key]) {
unset($array1[$key]);
continue;
}
if (is_array($val)) {
$val = diff($val, $array2[$key]);
if ($val !== false) {
$array1[$key] = $val;
}
}
}
return $array1;
}
$array1 = array(
array(
array('foo', 'bar', 'baz'),
0
)
);
$array2 = array(
array(
array('foo', 'bar')
)
);
var_dump(diff($array1, $array2));
If you're looking for differences in the values, how about array_diff_assoc. The http://us2.php.net/manual/en/function.array-diff-assoc.php">php manual says it "returns an array containing all the values from array1 that are not present in any of the other arrays" and gives the following example:
In this example you see the "a" =>
"green" pair is present in both arrays
and thus it is not in the ouput from
the function. Unlike this, the pair 0
=> "red" is in the ouput because in the second argument "red" has key
which is 1
<?php
$array1 = array("a" => "green", "b" => "brown", "c" => "blue", "red");
$array2 = array("a" => "green", "yellow", "red");
$result = array_diff_assoc($array1, $array2);
print_r($result);
?>
The above example will output:
Array
(
[b] => brown
[c] => blue
[0] => red
)
Is this what you're looking for?
Related
I have the following declaration of array
Array
(
[name] => 1
[callrate] => 1
[maxcalls] => 100000
[mintime] => 5
[maxtime] => 16
[skillexps] => Array
(
[0] => 1
[1] => 2
)
)
How can I check the the array contains the array. I tried the
function is_multi($a) {
foreach ($a as $v) {
if (is_array($v))
{
return "has array";
break;
}
break;
}
return 'only value';
}
But this only gives 'only value'. I need to check the If Associative Array is two dimensional.
Why your existing code doesn't work?
Because you're looking every element of array to check is it an array or not using foreach() and is_array()? if not then break; so when it checks for name element the value is not an array, it is just a integer so it immediately break; and goes out of the foreach()loop and returns only value but when I removed the extra break; from your code it works fine because then it checks for each and every element of your array to verify that is it contains an array or not . I've also added a good looking way how to check array is multi-dimensional or not. Hope this helps :)
function is_multi($a) {
foreach ($a as $v) {
if (is_array($v))
{
return "has array";
break;
}
// removed extra break; from here
}
return 'only value';
}
To check array is multi-dimensional or not? I'll do this way,
<?php
function is_multi(array $array) {
return count($array) !== count($array, COUNT_RECURSIVE);
}
$array = array
(
'name' => 1,
'callrate' => 1,
'maxcalls' => 100000,
'mintime' => 5,
'maxtime' => 16,
'skillexps' => array
(
1,
2
)
);
echo is_multi($array);
?>
DEMO: https://3v4l.org/LANsh
If you are trying to check whether the array is 2d or not , you can use array filter like below
$data=array
(
'name' => 1,
'callrate' => 1,
'maxcalls' => 100000,
'mintime' => 5,
'maxtime' => 16,
'skillexps' =>array(1,2)
);
$filteredItems = array_filter($data, function($elem) {
return is_array($elem);
});
if(count($filteredItems)>0){
echo "multi dimensional";
}
else{
echo "1 dimensional";
}
If you are interested to check every keys,you can use array_map with closure function like below
$data=array
(
'name' => 1,
'callrate' => 1,
'maxcalls' => 100000,
'mintime' => 5,
'maxtime' => 16,
'skillexps' => array
(
0 => 1,
1 => 2
)
);
$array = array_map(function ($a) {
return is_array($a) ? "has array" : "only value";
}, $data);
print_r($array);
output
Array
(
[name] => only value
[callrate] => only value
[maxcalls] => only value
[mintime] => only value
[maxtime] => only value
[skillexps] => has array
)
If you want to check entire array is multidimensional or not then just add one line below
$multi=array_search('has array', $array) ? "is multi " : "is not multi";
echo $multi;
Given an array, how do I convert array starting at key [1] from type string to type int?
Array
(
[0] => "id"
[1] => "6086220176"
[2] => "6542925762"
[3] => "6623113406"
[4] => "6702782948"
)
I've checked out related question how to convert array values from string to int? already, but I would like to skip the first key "id" int he conversion, and not all keys in array!
array_walk($array, function (&$value) {
if (ctype_digit($value)) {
$value = (int) $value;
}
});
var_export($array);
Output:
array (
0 => 'id',
1 => 6086220176,
2 => 6542925762,
3 => 6623113406,
4 => 6702782948,
)
$arr = array_merge(array($arr[0]),array_map('intval', array_slice($arr, 1)));
Output:
array(5) {
[0]=>
string(2) "id"
[1]=>
int(2147483647)
[2]=>
int(2147483647)
[3]=>
int(2147483647)
[4]=>
int(2147483647)
}
Demo.
$array = array($array[0]) + array_map('intval', $array);
(if you want to avoid a foreach loop)
php is loosely typed, you don't need to type cast it. It will do it for you. But if you want to explicitly do this, you can do like this:
$c = count($array)-1;
for ($n=1;$n<$c;$n++) {
$array[$n] = (int) $array[$n];
}
foreach($array as $key => $val){
if($key !== 0){
$array[$key] = (int) $val;
}
}
or
foreach($array as $key => $val){
if(is_numeric($val)){
$array[$key] = (int) $val;
}
}
If all you values are int :
<?php
$arr = array(
[0] => "id"
[1] => "6086220176"
[2] => "6542925762"
[3] => "6623113406"
[4] => "6702782948"
);
$arr = array_map(function($var) {
// Your 'id' is not an int and will not be converted.
return is_numeric($var) ? (int)$var : $var;
}, $arr);
foreach($array as $k => $v){
if($k == 0) continue;
$array[$k] = is_int($v) ? intval($v) : $v; // if it's not convertible to int it keeps the value
}
or if you have non-numeric indexes
$skipped = false;
foreach($array as $k => $v){
if($skipped === false){
$skipped = true;
continue;
}
$array[$k] = is_int($v) ? intval($v) : $v;
}
Another technique not yet mentioned on this page is to encode the array as a json string with the JSON_NUMERIC_CHECK flag so that numeric values are appropriately cast as integers or floats. Then decode the generated string back to an array.
This approach does not require the developer to know in advance the key/index of the value nor require a conditional check on each value to see if the value is numeric. In simple terms, it is highly portable as a general-use strategy.
This technique conveniently accommodates arrays with more than one level.
Code: (Demo)
$array = [
"id",
"6086220176",
"6542925762",
"6623113406",
"6702782948",
['333', [['444']]]
];
var_export(
json_decode(
json_encode(
$array,
JSON_NUMERIC_CHECK
),
true
)
);
Output:
array (
0 => 'id',
1 => 6086220176,
2 => 6542925762,
3 => 6623113406,
4 => 6702782948,
5 =>
array (
0 => 333,
1 =>
array (
0 =>
array (
0 => 444,
),
),
),
)
It's not clever to do this but this could probably works:
$narray = array();
foreach($array as $k => $v){
$narray[$k+1] = $v;
}
$array = $narray;
$array is your array you want to start with 1.
I got main array keys a1 and a2.
$array1 = array(a1=>array(200,300,300), a2=>array(100,600,200));
$array2 = array(a1=>array('gen','gen2','gen'), a2=>array('gen2','gen3','gen3'));
I want my output to be
'a1'=>array(
'gen'=>200
'gen2'=>300
'gen'=>300
),
'a2'=>array(
'gen2'=>100
'gen3' =>600
'gen3' =>200
)
or
'a1'=>array(
'gen'=>500
'gen2'=>300
)
'a2'=>array(
'gen2'=>100
'gen3'=>800
)
I have tried this code but not enough, It doesn''t show the duplicate or it's better if it shows the sum of of the value ofduplicate keys
<?php
$array1 = array(a1=>array(200,300,300), a2=>array(100,600,200));
$array2 = array(a1=>array('gen','gen2','gen'), a2=>array('gen2','gen3','gen3'));
$result = array();
foreach($array1 as $k => $v) {
$result[$k] = array_combine($array2[$k], $v);
}
print_r($result);
?>
Thanks you very much for your help
$array1 = array(
'a1' => array(200,300,300),
'a2' => array(100,600,200));
$array2 = array(
'a1' => array('gen','gen2','gen'),
'a2' => array('gen2','gen3','gen3'));
$result = array('a1' => array(), 'a2' => array());
foreach($array2 as $k => $v) {
foreach ($v as $k2 => $v2){
if (array_key_exists($v2, $result[$k])){
$result[$k][$v2] += $array1[$k][$k2];
} else {
$result[$k][$v2] = $array1[$k][$k2];
}
}
}
Output:
Array
(
[a1] => Array
(
[gen] => 500
[gen2] => 300
)
[a2] => Array
(
[gen2] => 100
[gen3] => 800
)
)
I have a multidimensional array as shown below. How do I change the keys that start with "id of"?
Array
(
[0] => Array
(
[id of ten] => 1871
[name] => bob
)
[1] => Array
(
[id of nine hundred thousand] => 12581
[name] => barney
)
)
Normally, you'd do something like:
foreach ( $array as $k=>$v )
{
$array[$k] ['id'] = $array[$k] ['old'];
unset($array[$k]['old']);
}
In my case, the key changes dynamically (there are thousands of keys in my multidimensional array and they are random but they will always start w/ "id of...")
thx!
I'm wondering if this is what you are looking for:
<?php
$array = array(
array(
"id of one" => 434,
"name" => "bob"
),
array(
"id of two" => 9323,
"name" => "ted"
)
);
$c_array = count($array);
for ($i = 0; $i < $c_array; $i++)
{
foreach ($array[$i] as $key => $value)
{
if (substr($key, 0, 5) == 'id of') {
$array[$i][substr($key, 6)] = $value;
unset($array[$i][$key]);
}
}
}
print_r($array);
?>
NOTE: Includes use of substr() instead of strpos(). See Gumbo's comment below.
https://ideone.com/xBV5L
This outputs:
Array
(
[0] => Array
(
[name] => bob
[one] => 434
)
[1] => Array
(
[name] => ted
[two] => 9323
)
)
This solution is very clean. Array_shift, does two things at once: returns first element (which has the id), and deletes it from the array, so you can directly assign it to the $new_array at 'id'
$new_arr=array();
foreach ( $array as $arr)
{
$new_arr[array_shift($arr)] = $arr;
}
If the 'id of' key is always the first element of the array, you can use the following:
foreach ($input as &$value)
{
$value['key'] = reset($value);
$key = key($value);
unset($value[$key]);
}
Otherwise, the following worked for me:
foreach ($input as &$value)
{
foreach ($value as $key=>$el) {
if (substr($key, 0, 5) == 'id of') {
$value['key'] = $el;
unset($value[$key]);
}
}
}
In both cases you can change $value['key'] to whatever you want the new key to be.
I know there's a ton of answers but I can't seem to get it right. I have the following arrays and what I've tried:
$a = array ( 0 => '1421' , 1 => '2241' );
$b = array ( 0 => 'teststring1' , 1 => 'teststring2' );
$c = array ( 0 => 'teststring3' , 1 => 'teststring4' );
$d = array ( 0 => 'teststring5' , 1 => 'teststring6' );
$e = array_combine($a, array($b,$c,$d) );
But with this I get the error array_combine() [function.array-combine]: Both parameters should have an equal number of elements.
I know it's because the $a's array values aren't keys. That's why I'm coming here to see if I could get some help with an answer that can help me make it look something like this:
array(2) {
[1421]=>array( [0] => teststring1
[1] => teststring3
[2] => teststring5
)
[2241]=>array( [0] => teststring2
[1] => teststring4
[2] => teststring6
)
}
If you have control over creating the arrays, you should create them like:
$a = array ('1421' ,'2241');
$b = array ('teststring1', 'teststring3', 'teststring5');
$c = array ('teststring2', 'teststring4', 'teststring6');
$e = array_combine($a, array($b,$c) );
If not, you have to loop over them:
$result = array();
$values = array($b, $c, $d);
foreach($a as $index => $key) {
$t = array();
foreach($values as $value) {
$t[] = $value[$index];
}
$result[$key] = $t;
}
DEMO
Here is a one-liner in a functional coding style. Calling array_map() with a null function parameter followed by the "values" arrays will generate the desired subarray structures. array_combine() does the key=>value associations.
Code (Demo)
var_export(array_combine($a, array_map(null, $b, $c, $d)));
Output:
array (
1421 =>
array (
0 => 'teststring1',
1 => 'teststring3',
2 => 'teststring5',
),
2241 =>
array (
0 => 'teststring2',
1 => 'teststring4',
2 => 'teststring6',
),
)
Super clean, right? I know. It's a useful little trick when you don't have control of the initial array generation step.
Here's a new version of array_merge_recursive which will handle integer keys. Let know how it goes.
$a = array ( 0 => '1421' , 1 => '2241' );
$b = array ( 0 => 'teststring1' , 1 => 'teststring2' );
$c = array ( 0 => 'teststring3' , 1 => 'teststring4' );
$d = array ( 0 => 'teststring5' , 1 => 'teststring6' );
$e = array_combine($a, array_merge_recursive2($b, $c, $d));
echo "<pre>";
print_r($e);
function array_merge_recursive2() {
$args = func_get_args();
$ret = array();
foreach ($args as $arr) {
if(is_array($arr)) {
foreach ($arr as $key => $val) {
$ret[$key][] = $val;
}
}
}
return $ret;
}