提问人:Ivan 提问时间:10/14/2022 最后编辑:Ivan 更新时间:10/20/2022 访问量:258
比较两个数组并以 github 样式呈现交集/差异
Compare two arrays and present intersections/differences in a github-style
问:
我有两个按字母顺序排序的数组。每个数组都包含唯一的值,但某些值将在两个数组之间共享。
示例阵列:
$src = ["apple", "cherry", "grape", "lemon", "orange", "strawberry"];
$dst = ["apple", "banana", "cherry", "orange", "pear"];
我想输出两个列表,因为它们是 github/style 中的文件比较或“差异检查器”,如下所示:
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.
我被困在寻找正确的方法来做到这一点。好的,我对两个数组都做了一个循环,但那又怎样?foreach
<ul>
<?php foreach($src as $src_item) : ?>
<li><?php echo $src_item; // what else??? ?></<li>
<?php endforeach; ?>
</ul>
答:
3赞
Snor
10/14/2022
#1
您可以简单地将数组组合为唯一项目(然后重新排序!然后,您可以循环新数组并检查原始 2 个数组中有哪些项目。
<?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.
2赞
mickmackusa
10/15/2022
#2
对于不能保证输入数组按字母顺序排序并且可能包含重复项的情况,我想出了以下脚本。
- 循环,直到至少一个阵列耗尽/消耗。如果您以后想使用这些原始数组,请复制或将我的代码片段包装在函数调用中。
- 如果两个值相同,请将它们推送到结果数组中的同一行中。
- 如果不完全相同,请确定哪些数组具有更接近的匹配值,并将该匹配之前的所有值作为单独的行推送到结果数组中。
- 循环完成后,请确保将所有剩余值推送到结果数组中。
代码:(演示)
$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)];
}
要可视化为表格,请执行以下操作:
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 may place unwanted drag on performance.in_array()
代码:(演示)
$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
];
}
评论
0赞
akinuri
4/4/2023
This looks much better than what I've came up with. If I'm not mistaken, the arrays are treated as queues. Two main operations are done on them: check if the tips are equal, or modify the arrays till the tips are equal. It's clever :)
0赞
mickmackusa
4/4/2023
Correct assessment -- two queues. It doesn't feel "elegant" to me, but maybe there isn't an elegant way to be had.
评论