检查一个数组的元素是否在PHP中的另一个数组中


130

我在PHP中有两个数组,如下所示:

人:

Array
(
    [0] => 3
    [1] => 20
)

通缉犯:

Array
(
    [0] => 2
    [1] => 4
    [2] => 8
    [3] => 11
    [4] => 12
    [5] => 13
    [6] => 14
    [7] => 15
    [8] => 16
    [9] => 17
    [10] => 18
    [11] => 19
    [12] => 20
)

如何检查“ 通缉犯”数组中是否包含任何人员”元素?

在此示例中,它应该返回,true因为20通缉犯中

Answers:


204

您可以使用array_intersect()

$result = !empty(array_intersect($people, $criminals));

8
除变量外,不能将Empty()与其他任何东西一起使用。
grantwparks

@grantwparks然后为什么在PHP文档中有关此功能的内容中,他们说“如果var存在并且具有非空,非零值,则返回FALSE。否则返回TRUE。以下内容被认为是空的:array()(一个空数组)”?来源:php.net/manual/en/function.empty.php
Pere

5
在链接到的页面上:“在PHP 5.5之前,empty()仅支持变量;任何其他操作都会导致解析错误。换句话说,以下内容将不起作用:empty(trim($ name))。相反,使用trim($ name)==否。”
Grantwparks 2013年

9
正如评论中提到的那样,我发现!empty 它无法按预期工作。相反,我使用了count()!count(array_intersect($people, $criminals));
Mattios550 '16

3
为什么在抛出致命错误时以65票的高分将其标记为答案?致命错误:无法在写入上下文中使用函数返回值?
Dave Heq

31

使用array_intersect()和count()(而不是空)没有什么错。

例如:

$bFound = (count(array_intersect($criminals, $people))) ? true : false;

2
它没有任何问题,但是count()不被认为是高性能的(如果您关心微优化,那就是)
Jake A. Smith

23

如果“空”不是最佳选择,那该怎么办:

if (array_intersect($people, $criminals)) {...} //when found

要么

if (!array_intersect($people, $criminals)) {...} //when not found

22

该代码无效,因为您只能将变量传递到语言构造中。empty()是一种语言构造。

您必须分两行执行此操作:

$result = array_intersect($people, $criminals);
$result = !empty($result);

问题不在于它是一种语言构造。问题在于它需要一个引用,而格雷格正在传递一个值。
Artefacto

1
来自php.net的@Artefacto“注意:因为这是语言结构而不是函数,所以不能使用变量函数来调用它。” 就像保罗说的那样。
Grantwparks 2013年

17

in_array与array_intersect的性能测试:

$a1 = array(2,4,8,11,12,13,14,15,16,17,18,19,20);

$a2 = array(3,20);

$intersect_times = array();
$in_array_times = array();
for($j = 0; $j < 10; $j++)
{
    /***** TEST ONE array_intersect *******/
    $t = microtime(true);
    for($i = 0; $i < 100000; $i++)
    {
        $x = array_intersect($a1,$a2);
        $x = empty($x);
    }
    $intersect_times[] = microtime(true) - $t;


    /***** TEST TWO in_array *******/
    $t2 = microtime(true);
    for($i = 0; $i < 100000; $i++)
    {
        $x = false;
        foreach($a2 as $v){
            if(in_array($v,$a1))
            {
                $x = true;
                break;
            }
        }
    }
    $in_array_times[] = microtime(true) - $t2;
}

echo '<hr><br>'.implode('<br>',$intersect_times).'<br>array_intersect avg: '.(array_sum($intersect_times) / count($intersect_times));
echo '<hr><br>'.implode('<br>',$in_array_times).'<br>in_array avg: '.(array_sum($in_array_times) / count($in_array_times));
exit;

结果如下:

0.26520013809204
0.15600109100342
0.15599989891052
0.15599989891052
0.1560001373291
0.1560001373291
0.15599989891052
0.15599989891052
0.15599989891052
0.1560001373291
array_intersect avg: 0.16692011356354

0.015599966049194
0.031199932098389
0.031200170516968
0.031199932098389
0.031200885772705
0.031199932098389
0.031200170516968
0.031201124191284
0.031199932098389
0.031199932098389
in_array avg: 0.029640197753906

in_array至少快5倍。请注意,一旦找到结果,我们就会“中断”。


感谢您提供基准。因此,如果您知道要处理小的数组,最好还是使用array_intersect()
Tokeeen.com

isset甚至更快。您可以使用bool val启用或禁用。此外,作为关键字的搜索值还应确保没有重复项。´array_intersect平均:0.52077736854553;in_array平均:0.015597295761108;isset平均:0.0077081203460693´
cottton,

1

您还可以如下使用in_array:

<?php
$found = null;
$people = array(3,20,2);
$criminals = array( 2, 4, 8, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20);
foreach($people as $num) {
    if (in_array($num,$criminals)) {
        $found[$num] = true;
    } 
}
var_dump($found);
// array(2) { [20]=> bool(true)   [2]=> bool(true) }

虽然array_intersect当然更方便使用,但事实证明,它在性能方面并不是真正的优越。我也创建了此脚本:

<?php
$found = null;
$people = array(3,20,2);
$criminals = array( 2, 4, 8, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20);
$fastfind = array_intersect($people,$criminals);
var_dump($fastfind);
// array(2) { [1]=> int(20)   [2]=> int(2) }

然后,我分别在http://3v4l.org/WGhO7/perf#tabshttp://3v4l.org/g1Hnu/perf#tabs上运行了两个代码片段,并检查了它们的性能。有趣的是,PHP5.6的总CPU时间(即用户时间+系统时间)是相同的,内存也相同。对于in_array,在PHP5.4下的总CPU时间要比array_intersect少,尽管这样做的间隔很小。


结果令人迷惑。仅运行一次就太快了,无法衡量任何差异。如果您每秒有数百或数千个请求,那么这些秒的间隔很快就会累加,因此,如果您认为您的应用程序需要扩展,我会坚持in_array执行。
Frank Forte

1

经过一段时间的研究,这是我这样做的一种方式。我想创建一个Laravel API端点来检查某个字段是否在“使用中”,所以重要的信息是:1)哪个数据库表?2)什么DB列?和3)该列中是否有与搜索字词匹配的值?

知道了这一点,我们可以构造我们的关联数组:

$SEARCHABLE_TABLE_COLUMNS = [
    'users' => [ 'email' ],
];

然后,我们可以设置我们要检查的值:

$table = 'users';
$column = 'email';
$value = 'alice@bob.com';

然后,我们可以使用array_key_exists()in_array()彼此执行一个两步组合,然后对truthy条件进行操作:

// step 1: check if 'users' exists as a key in `$SEARCHABLE_TABLE_COLUMNS`
if (array_key_exists($table, $SEARCHABLE_TABLE_COLUMNS)) {

    // step 2: check if 'email' is in the array: $SEARCHABLE_TABLE_COLUMNS[$table]
    if (in_array($column, $SEARCHABLE_TABLE_COLUMNS[$table])) {

        // if table and column are allowed, return Boolean if value already exists
        // this will either return the first matching record or null
        $exists = DB::table($table)->where($column, '=', $value)->first();

        if ($exists) return response()->json([ 'in_use' => true ], 200);
        return response()->json([ 'in_use' => false ], 200);
    }

    // if $column isn't in $SEARCHABLE_TABLE_COLUMNS[$table],
    // then we need to tell the user we can't proceed with their request
    return response()->json([ 'error' => 'Illegal column name: '.$column ], 400);
}

// if $table isn't a key in $SEARCHABLE_TABLE_COLUMNS,
// then we need to tell the user we can't proceed with their request
return response()->json([ 'error' => 'Illegal table name: '.$table ], 400);

我为Laravel特定的PHP代码道歉,但是我将其保留,因为我认为您可以将其作为伪代码阅读。重要的部分是两个if同步执行的语句。

array_key_exists()并且in_array()是PHP函数。

资源:

关于算法我上面显示的好处是,你可以做一个REST端点,例如GET /in-use/{table}/{column}/{value}(其中tablecolumnvalue是变量)。

你可以有:

$SEARCHABLE_TABLE_COLUMNS = [
    'accounts' => [ 'account_name', 'phone', 'business_email' ],
    'users' => [ 'email' ],
];

然后您可以发出GET请求,例如:

GET /in-use/accounts/account_name/Bob's Drywall (您可能需要对最后一部分进行uri编码,但通常不需要)

GET /in-use/accounts/phone/888-555-1337

GET /in-use/users/email/alice@bob.com

还要注意,没有人可以做:

GET /in-use/users/password/dogmeat1337因为password未在的允许列列表中列出user

祝你好运。


我不知道这与问题有什么关系,但我看了一下:我真的希望您永远不要在其中使用动态数据$SEARCHABLE_TABLE_COLUMNS!这大声尖叫-不管之间是否有试图屏蔽和过滤表和列字符串的“超安全框架查询构建器”!在结尾处,表和列字符串不能通过占位符(准备好的语句)添加,必须像一样直接插入SELECT ... FROM {$table} WHERE {$column} = :placeholder ....。Ofc依赖于适配器(mysql,mongo等),但是没有保存参数!请静态或否列表=)
棉布
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.