I have two arrays which are sorted alphabetically. Each array contains unique values, but some values will be shared between the teo arrays.
Sample arrays:
$src = ["apple", "cherry", "grape", "lemon", "orange", "strawberry"];
$dst = ["apple", "banana", "cherry", "orange", "pear"];
I'd like to output two lists as they were a file comparison or "diff checker" in github/style, like this:
1.apple 1.apple
2. 2.banana
3.cherry 3.cherry
4.grape 4.
5.lemon 5.
6.orange 6.orange
7. 7.pear
8.strawberry 8.
I'm stuck in finding the right way to do this. Okay, I do a foreach
loop for both arrays, but then what?
<ul>
<?php foreach($src as $src_item) : ?>
<li><?php echo $src_item; // what else??? ?></<li>
<?php endforeach; ?>
</ul>
CodePudding user response:
You could simply combine the arrays unique items (then re-sort it!) Then you can just loop the new array and check which items are in the original 2 arrays.
<?php
$src = ["apple", "cherry", "grape", "lemon", "orange", "strawberry"];
$dst = ["apple", "banana", "cherry", "orange", "pear"];
$combined_items = array_unique(array_merge($src, $dst));
sort($combined_items);
$new_array = [];
foreach($combined_items as $item){
$item1 = in_array($item, $src) ? $item : null;
$item2 = in_array($item, $dst) ? $item : null;
$new_array[] = [$item1, $item2];
}
// $new_array will contain ["apple","apple"], [null, "banana"], etc.
CodePudding user response:
For cases where the input arrays are not guaranteed to be alphabetically ordered and may contain duplicates, I've come up with the following script.
- Loop until at least one of the arrays is exhausted/consumed. It you want to use these original arrays later, make a copy or wrap my snippet in a function call.
- If both values are identical, push them into the same row in the result array.
- If not identical, determine which arrays has the closer matching value, and push all values before that match as individual rows into the result array.
- When the loop finishes, make sure to push all remaining values into the result array.
Code: (Demo)
$src = ["apple", "cherry", "grape", "lemon", "orange", "strawberry", "cherry", "cherry"];
$dst = ["apple", "banana", "cherry", "orange", "pear", "cherry"];
$result = [];
while ($src && $dst) {
if ($src[0] === $dst[0]) { // align identical values
$result[] = [array_shift($src), array_shift($dst)];
continue;
}
$earliestSrcMatch = array_search($src[0], $dst);
$earliestDstMatch = array_search($dst[0], $src);
if ($earliestSrcMatch === $earliestDstMatch) { //both false (not 0)
$result[] = [array_shift($src), null];
$result[] = [null, array_shift($dst)];
continue;
} elseif (
$earliestDstMatch === false
|| (
$earliestSrcMatch !== false
&& $earliestSrcMatch < $earliestDstMatch
)
) {
while ($dst && $src[0] !== $dst[0]) {
$result[] = [null, array_shift($dst)];
}
} elseif (
$earliestSrcMatch === false
|| $earliestSrcMatch > $earliestDstMatch
) {
while ($src && $src[0] !== $dst[0]) {
$result[] = [array_shift($src), null];
}
}
}
while ($src) {
$result[] = [array_shift($src), null];
}
while ($dst) {
$result[] = [null, array_shift($dst)];
}
To visualize as a table:
echo "<table border=1>
";
foreach ($result as $i => [$s, $d]) {
printf(
"<tr>
<td>%d</td>
<td>%s</td>
<td>%s</td>
</tr>\n",
$i,
$s,
$d
);
}
echo "</table>";
My take on @Snor's approach would be to set up two lookup arrays so that the performance benefits of key sorting and searching can be enjoyed. On relatively large arrays, iterated calls of in_array()
may place unwanted drag on performance.
Code: (Demo)
$src = array_combine($src, $src);
$dst = array_combine($dst, $dst);
$combined_items = $src $dst;
ksort($combined_items);
$result = [];
foreach ($combined_items as $item) {
$result[] = [
$src[$item] ?? null,
$dst[$item] ?? null
];
}