У меня есть список массивов (для этого примера я использую сотовые телефоны). Я хочу, чтобы иметь возможность искать несколько пар ключ / значение и возвращать его индекс родительского массива.
Например, вот мой массив:
// $list_of_phones (array) Array ( [0] => Array ( [Manufacturer] => Apple [Model] => iPhone 3G 8GB [Carrier] => AT&T ) [1] => Array ( [Manufacturer] => Motorola [Model] => Droid X2 [Carrier] => Verizon ) )
Я хочу иметь возможность сделать что-то вроде следующего:
// This is not a real function, just used for example purposes $phone_id = multi_array_search( array('Manufacturer' => 'Motorola', 'Model' => 'Droid X2'), $list_of_phones ); // $phone_id should return '1', as this is the index of the result.
Любые идеи или предложения о том, как я могу или должен это делать?
Возможно, это будет полезно:
/** * Multi-array search * * @param array $array * @param array $search * @return array */ function multi_array_search($array, $search) { // Create the result array $result = array(); // Iterate over each array element foreach ($array as $key => $value) { // Iterate over each search condition foreach ($search as $k => $v) { // If the array element does not meet the search condition then continue to the next element if (!isset($value[$k]) || $value[$k] != $v) { continue 2; } } // Add the array element's key to the result array $result[] = $key; } // Return the result array return $result; } // Output the result print_r(multi_array_search($list_of_phones, array())); // Array ( [0] => 0 [1] => 1 ) // Output the result print_r(multi_array_search($list_of_phones, array('Manufacturer' => 'Apple'))); // Array ( [0] => 0 ) // Output the result print_r(multi_array_search($list_of_phones, array('Manufacturer' => 'Apple', 'Model' => 'iPhone 6'))); // Array ( )
Как показывает вывод, эта функция возвращает массив всех ключей с элементами, которые соответствуют всем критериям поиска.
вы можете использовать array_intersect_key и array_intersect и array_search
check array_intersect_key php manual, чтобы получить массив элементов с соответствующими ключами
и array_intesect php manual для получения массива, если элементы с соответствующими значениями
u может получить значение ключа в массиве, используя $array[key]
и получить ключ значения в массиве, используя array_search $key = array_search('green', $array);
php.net/manual/en/function.array-search.php
Я закончил делать следующее. Это некрасиво, но работает очень хорошо. Для тех, кто читает, не стесняйтесь обновлять с помощью DRYer ответа:
// Variables for this example $carrier = 'Verizon'; $model = 'Droid X2'; $manufacturer = 'Motorola'; // The foreach loop goes through each key/value of $list_of_phones and checks // if the given value is found in that particular array. If it is, it then checks // a second parameter (model), and so on. foreach ($list_of_phones as $key => $object) { if ( array_search($carrier, $object) ) { if ( array_search($model, $object) ) { if ( array_search($manufacturer, $object) ) { // Return the phone from the $list_of_phones array $phone = $list_of_phones[$key]; } } } }
Работает как шарм.
Этот способ работает для многомерного массива, такого как ваш:
$test = array_intersect_key($list_of_phones, array(array("Manufacturer" => "Motorola", "Carrier" => "Verizon")));
Я расширил код MichaelRushton, добавив поддержку для разных операторов сравнения:
function multi_array_search ($array, $search) { $result = []; foreach ($array as $key => $value) { //iterate over each array element foreach ($search as $k => $v) { //iterate over each search condition $operator = $v[0]; $searchField = $v[1]; $searchVal = $v[2]; switch ($operator) { case '=': $cond = ($value[$searchField] != $searchVal); break; case '!=': $cond = ($value[$searchField] == $searchVal); break; case '>': $cond = ($value[$searchField] <= $searchVal); break; case '<': $cond = ($value[$searchField] >= $searchVal); break; case '>=': $cond = ($value[$searchField] < $searchVal); break; case '<=': $cond = ($value[$searchField] > $searchVal); break; } //if the array element does not meet the search condition then continue to the next element if ((!isset($value[$searchField]) && $value[$searchField] !== null) || $cond) { continue 2; } } $result[] = $key; //add the array element's key to the result array } return $result; } //incoming data: $phonesList = [ 0 => [ 'Manufacturer' => 'Apple', 'Model' => 'iPhone 3G 8GB', 'Carrier' => 'AT&T', 'Cost' => 100000 ], 1 => [ 'Manufacturer' => 'Motorola', 'Model' => 'Droid X2', 'Carrier' => 'Verizon', 'Cost' => 120000 ], 2 => [ 'Manufacturer' => 'Motorola', 'Model' => 'Droid X2', 'Carrier' => 'Verizon', 'Cost' => 150000 ] ]; var_dump(multi_array_search($phonesList, [ ['=', 'Manufacturer', 'Motorola'], ['>', 'Cost', '130000'] ] )); //output: array(1) { [0]=> int(2) }
Это то же самое, что и @Boolean_Type, но немного улучшило ситуацию.
function multi_array_search($array, $search) { $result = array(); foreach ($array as $key => $val) { foreach ($search as $k => $v) { // We check if the $k has an operator. $operator = '='; if (preg_match('(<|<=|>|>=|!=|=)', $k, $m) === 1) { // We change the operator. $operator = $m[0]; // We trim $k to remove white spaces before and after. $k = trim(str_replace($m[0], '', $k)); } switch ($operator) { case '=': $cond = ($val[$k] != $v); break; case '!=': $cond = ($val[$k] == $v); break; case '>': $cond = ($val[$k] <= $v); break; case '<': $cond = ($val[$k] >= $v); break; case '>=': $cond = ($val[$k] < $sv); break; case '<=': $cond = ($val[$k] > $sv); break; } if (( ! isset($val[$k]) && $val[$k] !== null) OR $cond) { continue 2; } } $result[] = $key; } return $result; }
Таким образом, вы можете просто выполнить поиск следующим образом:
$keys = multi_array_search($phonesList, array( 'Manufacturer' => 'Motorola', 'Cost >' => '130000', ));
Если найдено, у вас будет и массив таких индексов: array(1, 25, 33)
(Это только пример).