I have two multidimensional arrays with different number of elements:
$complete = array(array("24","G:\TVShows\24"),array("Lost","G:\TVShows\Lost"),array("Game of Thrones","G:\TVShows\Game of Thrones"));
$subset = array(array("24","G:\TVShows\24","English"));
The first one ($complete) is the complete list of my tv shows on disk (name of the show, path to files). The second one ($subset) come from my database and include the spoken language as a third column / element.
I would like to return the shows that I have on disk but that do not appear in databse. How can I compare those to array with different number of elements?
Thank you for your help!
Since its a multi leveled array, you could use and combine array_map() and serialize()/unserialize(). Consider this example:
$complete = array(
array("24","G:\TVShows\24"),
array("Lost","G:\TVShows\Lost"),
array("Game of Thrones","G:\TVShows\Game of Thrones"),
array("The Walking Dead","G:\TVShows\The Walking Dead"),
array("Breaking Bad","G:\TVShows\Breaking Bad"),
array("Heroes","G:\TVShows\Heroes"),
);
$subset = array(
array("24","G:\TVShows\24","English"),
array("The Walking Dead","G:\TVShows\The Walking Dead","English"),
array("Heroes","G:\TVShows\Heroes","English"),
);
$shows_not_in_db = array();
// properly format the subsets for comparison on complete
foreach($subset as $key_s => $value_s) {
array_pop($value_s); // remove the last element "English"
$subset[$key_s] = serialize($value_s);
}
// serialize each complete arrays
$complete = array_map('serialize', $complete);
$shows_not_in_db = array_map('unserialize', array_diff($complete, $subset)); // array diff them, then unserialize
print_r($shows_not_in_db);
Sample Output
Edit: For case insensitive comparisons, you may use this alternative:
$shows_not_in_db = array_map('unserialize', array_udiff($complete, $subset, 'strcasecmp'));
// sample: The walking dead - The Walking Dead
Related
I'm not sure the title really gets across what I'm asking, so here's what I'm trying to do:
I have an array of arrays with four integer elements each, ie.
Array(Array(1,2,3,4), Array(4,2,3,1), Array(18,3,22,9), Array(23, 12, 33, 55))
I basically need to remove one of the two arrays that have the same values in any order, like indices 0 and 1 in the example above.
I can do this pretty easily when there are only two elements to check, using the best answer code in this question.
My multidimensional array can have 1-10 arrays at any given time, so I can't seem to figure out the best way to process a structure like that and remove arrays that have the same numbers in any order.
Thanks so much!
I've been thinking about this, and I think using a well designed closure with array_filter might be the way I'd go about this:
$matches = array();
$array = array_filter($array, function($ar) use (&$matches) {
sort($ar);
if(in_array($ar, $matches)) {
return false;
}
$matches[] = $ar;
return true;
});
See here for an example: http://ideone.com/Zl7tlR
Edit: $array will be your final result, ignore $matches as it's just used during the filter closure.
Let's say I have an array like so:
array(
[0]=>1
[1]=>3
[3]=>5
[15]=>6
);
Arbitrarily I want array[15] to be the first:
array(
[15]=>6
[0]=>1
[1]=>3
[3]=>5
);
What is the fastest and most painless way to do this?
Here are the things I've tried:
array_unshift - Unfortunately, my keys are numeric and I need to keep the order (sort of like uasort) this messes up the keys.
uasort - seems too much overhead - the reason I want to make my element the first in my array is to specifically avoid uasort! (Swapping elements on the fly instead of sorting when I need them)
Assuming you know the key of the element you want to shift, and that element could be in any position in the array (not necessarily the last element):
$shift_key = 15;
$shift = array($shift_key => $arr[$shift_key]);
$arr = $shift + $arr;
See demo
Updated - unset() not necessary. Pointed out by #FuzzyTree
You can try this using a slice and a union operator:
// get last element (preserving keys)
$last = array_slice($array, -1, 1, true);
// put it back with union operator
$array = $last + $array;
Update: as mentioned below, this answer takes the last key and puts it at the front. If you want to arbitrarily move any element to the front:
$array = array($your_desired_key => $array[$your_desired_key]) + $array;
Union operators take from the right and add to the left (so the original value gets overwritten).
If #15 is always last you can do
$last = array_pop($array); //remove from end
array_unshift($last); //push on front
To reorder the keys for sorting simply add
$array = array_values($array); //reindex array
#Edit - if we don't assume its always last then I would go with ( if we always know wwhat the key is, then most likely we will know its position or it's not a numerically indexed array but an associative one with numeric keys, as op did state "arbitrarily" so one has to assume the structure of the array is known before hand. )
I also dont see the need to reindex them as the op stated that it was to avoid sorting. So why would you then sort?
$item = $array[15];
unset($array[15]); //....etc.
I personally like that title. My question is about the simplest and yet most secured way to find out if an array is contained in another array of arrays.
Here's my sample code to explaine a little bit more clear:
$container = array();
$array1 = array('A','B','C');
$container[] = $array1;
$array2 = array();
$array2[2] = 'C';
$array2[1] = 'B';
$array2[0] = 'A'; //now, the array is physically the same as $array1
if (in_array($array2,$container)) {
echo "is inside";
}
If I have more complex array (no objects in it) which contains several keys which may get added in different order, but are physically the same, does in_array compare reliable, or do I have to check every key itself?
You car use the native function PHP array_walk_recursive with your custom callback.
I m having trouble checking if a comma separated string contains another comma separated string.
Suppose I have two strings
$stringA="red,blue,yellow,green,black,grey,purple,pink,khaki,lemon,orange,white,maroon";
$stringB="blue,green,white,pink,maroon";
All I want to check is whether colors in $stringB is contained in $stringA or not?? The only way I could think of is converting $stringA into an array, and checking the colors one by one using in_array function. Is there another easier way around?
Thanks in advance
$stringA="red,blue,yellow,green,black,grey,purple,pink,khaki,lemon,orange,white,maroon";
$stringB="blue,green,white,pink,maroon";
$arrayA = explode(',', $stringA);
$arrayB = explode(',', $stringB);
$min = min(array(
count($arrayA),
count($arrayB),
));
$AcontainsB = ($min == count(array_intersect($arrayA, $arrayB)));
I think comparing arrays is not bad idea, but you can also do something like that:
$stringATmp = ','.$stringA.',';
$colors = explode(',', $stringB);
$contains = true;
foreach ($colors as $color) {
if (strpos($stringATmp, ','.$color.',') === false) {
$contains = false;
break;
}
}
There are ways of doing it that are faster than others, but no ways that are conceptually easier than loading the data into some kind of data structure. Since you are talking about checking a list of items in arbitrary order against another list of items that can be in arbitrary order, there are no shortcuts around getting the reference list (stringA) into a data structure, and then looking up the stringB list in that data structure.
One way to speed it up.
Explode stringA into an array.
array flip the stringA array so that the colors become keys in the array (it does not matter what the values are).
Now you can look up each color from an exploded String B by with code like the following:
Something like this:
$stringAArray = explode(',', $stringA);
$stringAArray = array_flip($stringAArray);
$stringBArray = explode(',',$stringB);
$itemsToFind = count($stringBArray);
foreach ($stringBArray as $colorFromB) {
if (array_key_exists($colorFromB, $stringAArray)) {
$itemsToFind--;
}
}
if ($itemsToFind == 0) {
echo "All B items are in A"
}
This is a very fast lookup and scales well for lots of items in A and B.
Final note: for smallish arrays, doing it via in_array is going to be comparably fast.
So far I have done the following:
$row = mysql_fetch_assoc($result);
$row2 = mysql_fetch_assoc($result);
$duplicates = array_intersect($row, $row2);
How do I combine the 2 arrays and make a new one that just contains one instance of the previously repeated variables? (so if array $row contained the variable 'apple' 2 times and the array $row2 contained the variable 'apple' 3 times, in the new, merged array, 'apple' would only appear once.
edit: I didn't realize that the array_merge() function works differently for numbers than compared to strings. I gave the 'apple' example above but my arrays are dealing with product IDs which are numbers. PHP manual says
If, however, the arrays contain numeric keys, the later value will not
overwrite the original value, but will be appended.
and I need help in merging arrays with numbers, what should I do?
You can use
$c = array_merge($a, $b);
http://php.net/manual/en/function.array-merge.php
if you want to remove duplicate values after the merge then use array_unique();
so...
$c = array_unique(array_merge($a, $b));