Reputation: 117
I have a multidimensional array which outputs data as such (this gets filled with a foreach looping over specific items):
Array
(
[1] => Array
(
[0] => 0
)
[3] => Array
(
[0] => 0
[1] => 1
[2] => 2
)
[9] => Array
(
[0] => 2
)
)
The first keys are id's of specific items, the keys on the second level are of no meaning/importance, the values however are.
As you can see in this example, the value 0
exists both in 1
and 3
, and the value 2
existst in both 3
and 9
and only 1
is unique. What I'd like to achieve here is to check if any value exists within multiple items (as is here the case) and have some way of keeping track where certain values are duplicated.
How would I go about doing this? I've tried implementing multiple solutions, including the ones found here, but whatever I try, it doesn't quite seem to work the way I'd like it to.
Many thanks to whoever can help me out or point me in the right direction.
Upvotes: 1
Views: 3337
Reputation: 3220
What you're looking for is in fact array_intersect and pass the array values as parameters.
Using php from 5.6 you can pass the array using variadic functions.
array_intersect(...array_values($array));
This will show you the values that are repeated all over the array.
And in the end to get the unique repeated values over the single element against the others:
$repeated = [];
foreach (array_values($array) as $analyzed_part) {
array_map(function ($array_piece) use ($analyzed_part, &$repeated) {
// Skip the current
if ($analyzed_part != $array_piece) {
$repeated[] = array_intersect($analyzed_part, $array_piece);
}
}, $array);
}
// Here you have all the repetitions between one element and the other
var_dump($repeated);
// Get the unique values
$unique_repeated = array_unique(array_merge(...$repeated));
var_dump($unique_repeated);
Upvotes: 0
Reputation: 2875
I like Aron Cederholm's answer, but another option you could go for you that might provide you with plenty of information is to make a kind of reverse associative array, where the values become keys and vice versa. Here's what I mean (based on Aron's initial loop):
$valueMap = [];
foreach ($outerArray as $id => $innerArray) {
foreach ($innerArray as $value) {
if (!isset($valueMap[$value])) $valueMap[$value] = [$id];
else $valueMap[$value][] = $id;
}
}
This has the benefit of giving you and array indexed by value, and for each value you can see which indices of the original array contain that value, if that makes sense. You can then check how many items contain the value you're looking for with
count($valueMap[$value])
And the item at $valueMap[$value] gives you an array of indices where those values can be found, which answers your "keep track of values" problem, right?
The downside is you've now doubled the amount of memory being used.
Upvotes: 0
Reputation: 6013
You can do this to detect if you have duplicates
$mergedValues = [];
foreach ($outerArray as $id => $innerArray) {
$mergedValues = array_merge($mergedValues, $innerArray);
}
$uniqueValues = array_unique($mergedValues);
if (sizeof($uniqueValues) != sizeof($mergedValues)) {
echo 'You have duplicates!', PHP_EOL;
echo 'These are duplicates: ', implode(', ', array_unique(array_diff_assoc($mergedValues, $uniqueValues))), PHP_EOL;
}
Upvotes: 1