测试一个数组是否是另一个数组的子集。

28

如何确定一个数组是否为另一个数组的子集(第一个数组中的所有元素都在第二个数组中出现)?

 $s1 = "string1>string2>string3>string4>string5>string6>";
 $arr1 = explode(">", $s1);
 $s2 = "string1>string4>string5";
 $arr2 = explode(">", $s2);

 $isSubset = /* ??? */
6个回答

76
if (array_intersect($array1, $array2) == $array1) {
    // $array1 is a subset of $array2
}

1
array_intersect :) ,好的解决方案 - shail
4
好的,array_diff实际上更加优雅。 :) - deceze
array_diff(['a', 'b', 'c'], ['a', 'b']) 将返回 ['c']。然而,array_diff(['c'], ['d']) 也将返回 ['c'],因此实际上它并不是一种优雅的解决方案。 - aleemb
2
@aleemb 嗯...如果array_diff的结果不是一个空数组,那么这个数组就不是另一个数组的子集。如果结果是一个空数组,那么它就是一个子集。所以,你的例子中的结果是预期的、正确的,也正是我们想要的。 - deceze
更加直观的答案。谢谢! - Ulad Kasach
显示剩余3条评论

31

简单:使用数组减法。

通过数组减法,你可以知道一个数组是否是另一个数组的子集。

示例:

if (!array_diff($array1, $array2)) {
    // $array1 is a subset of $array2
}

参考: array_diff

你也可以使用array_intersect

试试看。


1
array_diff(['a', 'b', 'c'], ['a', 'b']) 将返回 ['c']。然而,array_diff(['c'], ['d']) 也将返回 ['c'],因此实际上它并不是一种优雅的解决方案。 - aleemb
1
如果你的数组中每个键都有特定类型,那么在比较多维数组时,array_diff_assoc更加安全。 - Tez
5
我明白您的意思。对于这个解决方案:array_diff(['a', 'b','c'], ['a', 'b']) 返回 ['c'],这意味着数组1不是数组2的子集 --> 正确。array_diff(['c'], ['d']) 返回 ['c'],这意味着数组1不是数组2的子集 --> 正确。有什么问题吗? - alumi
我认为一个问题是这个解决方案难以思考。array_intersect 解决方案没有否定,并且不涉及数学。它很容易在脑海中可视化。 - datashaman
但是array_diff将两者都转换为字符串,因此如果您有两个对象数组,则会出现错误“无法将类_____的对象转换为字符串”。 - Someone_who_likes_SE

20
如果您从字符串开始,可以检查 strstr($fullString,$subsetStr);。但是它只适用于所有字符具有相同顺序的情况: 'abcd','cd'将有效,但'abcd','ad'则无法正常工作。
但是,与其编写自己的自定义函数,您应该知道PHP拥有大量的数组函数,因此几乎不可能没有std函数可以完成您需要做的任务。在这种情况下,我建议使用array_diff
$srcString = explode('>','string1>string2>string3>string4>string5');
$subset = explode('>','string3>string2>string5');
$isSubset = array_diff($subset,$srcString);
//if (empty($isSubset)) --> cf comments: somewhat safer branch:
if (!$isSubset)
{
    echo 'Subset';
    return true;
}
else
{
    echo 'Nope, substrings: '.implode(', ',$isSubset).' Didn\'t match';
    return false;
}

1
请参考PHP的isset和empty指南了解原因。 - deceze
3
谢谢,但正如所说:这里没有真正的区别:“empty” === “false”的松散比较,因此“empty($var)”和“!$var”是可以互换的。据我所知,唯一的好处是当“$var”未定义时,“!$var”会抛出错误。在上面的代码片段中不可能发生这种情况。不过为了以防万一某个人决定在“array_diff”和“if()”之间添加大量代码,我会编辑我的答案。 - Elias Van Ootegem
2
没错。你应该只在变量可能不存在的情况下使用empty。否则,你就会不必要地放弃 PHP 错误报告的优势。这只是一个经验法则,你应该遵循它,以便通过不抑制错误报告来使自己的生活更轻松。 - deceze
4
我不介意被贬值,但我在乎人们不费心解释为什么。 - Elias Van Ootegem
1
$isSubset 应该改名为 $isntSubset,不是吗? - Dan Chadwick
显示剩余2条评论

1
我会创建一个与较大数组相关联的关联数组,然后遍历较小数组,寻找非冲突项,如果找到,则返回 false。
function isSubset($arr1,$arr2){
    $map = Array();
    for ($i=0;$i<count($arr1);$i++){
      $map[$arr[$i]]=true;
    }
    for ($i=0;$i<count($arr2);$i++){
       if (!isset($map[$arr2[$i]])){
          return false;
       }
    }
    return true;

4
这是我见过的最复杂的 array_flip - deceze
这实际上是你可以使用的最简单的array_flip方法。这几乎肯定是array_flip背后发生的事情。但感谢您告诉我这个函数。很好知道。 - ajon

1
$s1 = "1>2>3>4>5>6>7";

$arr1 = explode(">",$s1);

$s2 = "1>2>3";

$arr2 = explode(">",$s2); 

if(isSub($arr1,$arr2)){

         echo 'true';

}else{

         echo 'false';
}

function isSub($a1,$a2){

    $num2 = count($a2);
    $sub  = $num2;

    for($i = 0;$i < $num2 ;$i++){
        if(in_array($a2[$i],$a1)){
            $sub--;
        }
    }
    return ($sub==0)? true:false;
}

0

这是一个简单的函数,如果数组是精确子集,则返回true,否则返回false。该解决方案也适用于二维数组。

 function is_array_subset($superArr, $subArr) {
        foreach ($subArr as $key => $value) {
            //check if keys not set in super array OR values are unequal in both array.
            if (!isset($superArr[$key]) || $superArr[$key] != $value) {
                return false;
            }
        }
        return true;
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接