Page 1 of 1

[SOLVED] How to find if two multidimensional arrays match

Posted: Sun Sep 24, 2006 9:25 pm
by Stryks
Hi all,

I have two mutidimensional arrays holding information about assorted products and upgrades.

This first is the prepared information of a new item to be added, and the second is a list of items in the cart. I want to loop through the second array and compare it to the first, returning a true or false answer to if they match.

The objective is that if an item to be added to the cart matches one already there, it will just increase the count instead of adding a second identical item.

I'm sure I could tack together some obscure code to do it but I thought I 'd check to see if anyone had any ideas to help get it done a bit better.

Thanks

Posted: Sun Sep 24, 2006 9:28 pm
by feyd
array_walk() or array_diff() could be useful possibly.

Posted: Sun Sep 24, 2006 9:44 pm
by Stryks
Yeah, I've been looking at array_diff(), but mainly I'm concerned with how messy I'm going to make it when I try and use it recursively.

I'll take a closer look at array_walk() but I never seem to be able to get it to do exactly what I want. Of course, I've never used it to try and do this so this may be what it is good for.

Thanks

Posted: Sun Sep 24, 2006 10:13 pm
by Stryks
See, this is my constant fear .... I'm always going to come up with the most boring way to do it ....

Code: Select all

<?php 
$sweet = array('a' => 'apple', 'b' => 'banana');
$fruits = array('sweet' => $sweet, 'sour' => 'lemon');
$sweet = array('a' => 'apples', 'b' => 'banana');
$vegies = array('sweet' => $sweet, 'sour' => 'lemon');

function arr_identical($test_arr_1, $test_arr_2) {
	if(is_array($test_arr_1)) {
		foreach($test_arr_1 as $id_1=>$value_1) {
			if(isset($test_arr_2[$id_1])) {
				if(is_array($value_1)) {
					if(!arr_identical($value_1, $test_arr_2[$id_1])) return false;
				} else {
					if(!($value_1 === $test_arr_2[$id_1])) return false;
				}
			} else return false;
		}		
	}
	return true;
}

if(arr_identical($fruits, $vegies)) echo "They Matched"; else echo "They Didnt Match";

?>
It works I guess .... but can anyone give me a cleaner / faster method?

Posted: Mon Sep 25, 2006 4:28 am
by Stryks
Actually, that didn't really work that well after all. If the second array had values that the first one didnt but otherwise matched, it returned true.

This fixes it:

Code: Select all

$sweet = array('a' => 'apple', 'b' => 'banana');
$fruits = array('sweet' => $sweet, 'sour' => 'lemon');
$sweet = array('a' => 'apple', 'b' => 'banana');
$vegies = array('sweet' => $sweet, 'sour' => 'lemon', 'bitter' => 'vinegar');

function arr_identical($test_arr_1, $test_arr_2) {
	if((is_array($test_arr_1)) && (is_array($test_arr_2))) {
		if(count($test_arr_1) == count($test_arr_2)) {
			foreach($test_arr_1 as $id_1=>$value_1) {
				if(isset($test_arr_2[$id_1])) {
					if(is_array($value_1)) {
						if(!arr_identical($value_1, $test_arr_2[$id_1])) return false;
					} else {
						if(!($value_1 === $test_arr_2[$id_1])) return false;
					}
				} else return false;
			}		
		} else return false;
	} else return false;
	return true;
}

if(arr_identical($fruits, $vegies)) echo "They Matched"; else echo "They Didnt Match";
Still .... I feel like I'm tackling this the wrong way. I've tried to use the functions mentioned earlier, but I dont know .... I cant seem to wrangle a solution out of it.

If anyone can offer a cleaner alternative, it'd be greatly appreciated.

Posted: Mon Sep 25, 2006 7:44 am
by mickd
Since i've never used array_diff before i'm just assuming that something like this should work.

Code: Select all

<?php

function array_identical($array_1, $array_2) {

if(empty(array_diff($array_1, $array_2)) && empty(array_diff($array_2, $array_1)) {

return true;

} else {

return false;

}

}

?>

Posted: Mon Sep 25, 2006 10:40 am
by bokehman
I really see this as a problem with the coding prior to this point. If all your items have a unique id use this as you array key. Example:

Code: Select all

<?php

$items = array('dog' => 'dog', 'dogfood' => 'dogfood');
$cart = array();

# buy a dog
@$cart[$items['dog']]++;

#buy dog food
@$cart[$items['dogfood']]++;

#buy more dog food
@$cart[$items['dogfood']]++;

# look in cart
print_r($cart);

?>

Posted: Mon Sep 25, 2006 11:57 pm
by Stryks
mickd - I'll give that a whirl and see how I go. You know I actually did play with that but I just couldnt seem to get what I wanted. Hopefully your approach will help.

bokehman - Unfortunately, my cart is much more complex than that, with items being made up of various key components, and multiple optional upgrades / downgrades on multiple categories.

To make it more complex, there is the ability to save a set of options for a product as a custom item for later re-purchase.

The task I am working at here is making sure that if a custom item is added and then a stock item is customised to be the same end product, instead of adding a second item we just increment the existing one; hence the need to compare a multidimensional array of unknown complexity.


Thanks for the feedback guys.

Posted: Tue Sep 26, 2006 2:14 am
by Stryks
Here is the recursive function using array_diff

Code: Select all

function arr_identical($array_1, $array_2) {
	$test_1 = array_diff($array_1, $array_2);
	$test_2 = array_diff($array_2, $array_1);
	
	if(empty($test_1) && empty($test_2)) {
		foreach($array_1 as $key=>$value) 
			if(is_array($value)) return arr_identical($value, $array_2[$key]);
			else return true;
	} else return false;
}
I cant for the life of me find a use for array_walk though. it looks so promising but I cant really get it to do anything useful (apart from echoing info);

Any advances on this ?

Posted: Tue Oct 03, 2006 1:35 am
by Stryks
I seem to be pumping away at my own thread here. Seems a bit harder to get assistance lately, but I guess you can only ask and hope.

Anyhow ... I'm just updating this in case someone else needs a solution to a similar problem.

The previos code had a bug where it only checked the first element of the array to see if it was an array requiring a iteration. This revision also uses array_diff_assoc to ensure that both the keys and values match.

Code: Select all

function arr_identical($array_1, $array_2) {
   $test_1 = array_diff_assoc($array_1, $array_2);
   $test_2 = array_diff_assoc($array_2, $array_1);
	
   if(empty($test_1) && empty($test_2)) {
      foreach($array_1 as $key=>$value) 
         if(is_array($value)) return arr_identical($value, $array_2[$key]);
   } else return false;
   return true;
}
Cheers