Ответ 1
Вы можете использовать array_intersect()
.
$result = !empty(array_intersect($people, $criminals));
У меня есть два массива в 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
находится в розыске преступников.
Вы можете использовать array_intersect()
.
$result = !empty(array_intersect($people, $criminals));
Не так уж плохо с использованием array_intersect() и count() (вместо пустого).
Например:
$bFound = (count(array_intersect($criminals, $people))) ? true : false;
если "empty" - не лучший выбор, что об этом:
if (array_intersect($people, $criminals)) {...} //when found
или
if (!array_intersect($people, $criminals)) {...} //when not found
Этот код недействителен, поскольку вы можете передавать только переменные в языковые конструкции. empty()
- это языковая конструкция.
Вы должны сделать это в двух строках:
$result = array_intersect($people, $criminals);
$result = !empty($result);
Тест производительности для in_array vs 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 раз быстрее. Обратите внимание, что мы "ломаем", как только результат найден.
Вы также можете использовать 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, безусловно, более удобен в использовании, оказывается, что он не является превосходным с точки зрения производительности. Я также создал этот script:
<?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#tabs и http://3v4l.org/g1Hnu/perf#tabs и проверить производительность каждого из них. Интересно то, что общее время процессора, то есть время пользователя + системное время для PHP5.6 одинаково, а также то же самое. Общее время процессора в PHP5.4 меньше для in_array, чем array_intersect, хотя и незначительно.
Вот способ, которым я делаю это после исследования в течение некоторого времени. Я хотел создать конечную точку API Laravel, которая проверяет, используется ли поле, поэтому важная информация: 1) какая таблица БД? 2) какой столбец БД? и 3) есть ли в этом столбце значение, соответствующее условиям поиска?
Зная это, мы можем построить наш ассоциативный массив:
$SEARCHABLE_TABLE_COLUMNS = [
'users' => [ 'email' ],
];
Затем мы можем установить наши значения, которые мы проверим:
$table = 'users';
$column = 'email';
$value = '[email protected]';
Затем мы можем использовать array_key_exists()
и in_array()
с eachother, чтобы выполнить одно-, двухэтапное комбо и затем truthy
условие 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}
(где table
, column
и value
являются переменными).
Вы могли бы иметь:
$SEARCHABLE_TABLE_COLUMNS = [
'accounts' => [ 'account_name', 'phone', 'business_email' ],
'users' => [ 'email' ],
];
и тогда вы можете сделать GET-запросы, такие как:
GET/in-use/accounts/account_name/Bob Drywall
(вам может понадобиться кодировать uri последнюю часть, но обычно нет)
GET/in-use/accounts/phone/888-555-1337
GET/in-use/users/email/[email protected]
Обратите внимание, что никто не может сделать:
GET/in-use/users/password/dogmeat1337
потому что password
не указан в списке разрешенных для user
столбцов.
Удачи в вашем путешествии.