Вот данные
$array = array( 'random' => 1, 'pewpew' => 2, 'temp' => 5, 'xoxo' => 3, 'qweqweqe' => 4, ); $fields = array('random', 'xoxo', 'temp');
Мне нужно получить результат:
$result = array( 'random' => 1, 'xoxo' => 3, 'temp' => 5, );
Я имею в виду, что наличие / порядок ключей из $ полей применяется к массиву $.
Возникает вопрос: могу ли я выполнить это преобразование, используя только функции array_? (Я не хочу использовать iteations) Если да: вы можете связать мне функцию, которая мне нужна?
(извините за орфографические ошибки)
UPD.
PHP 5.2
Этот код сохраняет порядок и работает в PHP 5.2 по мере необходимости
Одна линия:
$result = array_merge( array_flip($fields), array_intersect_key( $array, array_flip( $fields ) ) );
Для производительности:
$flip = array_flip($fields); $result = array_merge( $flip array_intersect_key( $array, $flip ) );
$result=array_intersect_key($array ,array_flip($fields) );
// little trick required here... $fields = array('random' => 0, 'xoxo' => 0, 'temp' => 0); $result = array_intersect_key($array,$fields);
Меня всегда интересуют эти типы вопросов, где речь идет об эффективном коде (как в использовании кода, так и в скорости). Тем не менее, я пробовал и сравнивал несколько разных методов, и ничто не было столь же эффективным и простым foreach
!
Я пробовал все размещенные решения и свой собственный массив_валют и базовый foreach. Я провел несколько тестов, как с массивами, так и с полями, размещенными Miraage, а некоторые с гораздо большими массивами. Я также заметил что-то странное с результатами, например, дополнительные значения, если $ fields имели значения не в $ array.
Я заказал его по скорости.
$result = array(); foreach ($fields as $k) { if (isset($array[$k])) $result[$k] = $array[$k]; }
$result = array_diff_key($fields, $array);
function array_filter_by_key($array, $fields) { $result = array(); foreach ($fields as $k) { if (isset($array[$k])) $result[$k] = $array[$k]; } return $result; }
function array_walk_filter_by_key($item, $key, $vars) { if (isset($vars[1][$item])) $vars[0][$item] = $vars[1][$item]; } $result = array(); array_walk($fields, 'array_walk_filter_by_key', array(&$result, &$array));
$result = array(); reset($fields); while (list($key, $value) = each($fields)) { if (isset($array[$value])) $result[$value] = $array[$value]; }
$result = array_intersect_key($array, array_flip($fields));
$result = array_replace( array_fill_keys($fields, false), array_intersect_key($array, array_flip($fields)) );
$flip = array_flip($fields); $result = array_replace( array_intersect_key($flip, $array), array_intersect_key($array, $flip) );
function array_walk_filter_by_key_null(&$item, $key, $array) { if (isset($array[$key])) $item = $array[$key]; else $item = null; } $result = array_flip($fields); array_walk($result, 'array_walk_filter_by_key_null', $array);
$flip = array_flip($fields); $result = array_intersect_key( array_replace($flip, $array), array_intersect_key($flip, $array) );
$result = array_splice( array_merge(array_flip($fields), $array), 0, count($fields) );
-во$result = array_splice( array_merge(array_flip($fields), $array), 0, count($fields) );
Так оно и есть. Не могу победить DIY. Иногда восприятие заключается в том, что встроенные функции выполняются быстрее, но это не всегда так. В наши дни компиляторы очень хороши.
Я считаю, что это работает так, как вам нужно.
$result = array_splice(array_merge(array_flip($fields) , $array) , 0 , count($fields));
Чтобы решить головоломку:
$result = array_replace( array_intersect_key(array_flip($fields), $array), array_intersect_key($array, array_flip($fields)) );
Первый array_intersect создает список полей в хорошем порядке, другой – с помощью функции array_replace, чтобы создать ключи, которые не существуют в первом массиве.
Отвечает вашим требованиям. Но я бы не использовал его в любом производственном коде, поскольку это может быть довольно тяжелым (я не тестировал, так что это всего лишь ощущение кишки). Решение array_walk кажется легче.
Если вы хотите сохранить порядок ключей из $fields
, вы можете попробовать следующее: (если ключ не существует в $array
, тогда значение для этого ключа будет равно null.)
$result = array_flip($fields); array_walk($result, function(&$item, $key, $array) { $item = isset($array[$key]) ? $array[$key] : null; }, $array); var_dump($result);
Я буду считать, что вы не можете изменить ввод (ни $ array, ни $ fields).
Это может быть достигнуто, если у вас есть массив, который использует в качестве ключей значения из полей $. После этого вы можете объединить два (с $ полями, являющимися первым параметром) и удалить дополнительные элементы.
Учитывая, что вы не можете изменить $ fields, я создам его:
$tmp = array_combine($fields, range(1, count($fields))); $result = array_merge($tmp, $array); $result = array_splice($result, 0, count($fields));
Полный рабочий образец (с некоторыми комментариями) можно найти здесь: http://codepad.org/H0CDN7ok
Моя попытка:
array_replace( array_fill_keys($fields, false), array_intersect_key($array, # Keys in array, without order array_flip($fields))));
Легко было получить ключи в том же порядке, что и $ array. Затем, чтобы получить их в правильном порядке, я построил массив с ключами, равными $ полям. Остальное оставило Array_replace.
Решение «стабильно» в том, что недостающие ключи в массиве $ array будут заменены FALSE и, таким образом, могут быть отфильтрованы, если потребуется.
array_flip ходит массив полей размером N один раз, array_intersect ходит M раз, когда массив размером N, array_fill_keys стоит N, а final array_replace – это, я считаю, N ^ 2.
Таким образом, общая стоимость M * N ^ 5.
Прогуливаясь по самому маленькому массиву и выбирая значения из большого, это O (M ^ 2 * N ^ 2), поэтому при больших значениях NI подозревают, что PHP-решение может оказаться быстрее. Это не вводит ключи, которые не находятся в массиве данных.
$answer = array(); foreach($fields as $fld) // N-sized cycle if (isset($array[$fld])) // Cost M $answer[$fld] = // Assignment is N*1/2 $array[$fld]; // Getting value is another M
(спустя некоторое время и много озадачен)
Я проверил чек, и я думаю, что я должен совершить какую-то глупую ошибку, потому что время, которое я получаю, абсолютно бессмысленно. По общему признанию, я использую очень короткий массив $ fields, поэтому я бы ожидал искаженных результатов, но не искажал. Если $ answer [$ fld] вычисляется с помощью некоторого ДЕЙСТВИТЕЛЬНО умного хеш-трюка, согласно которому истинная стоимость интерпретируемого решения не является O (M ^ 2 * N ^ 2), а O (K * N ^ 2) с K малой.
Если кто-то хочет играть со временем или сказать мне, какую глупую ошибку я мог бы сделать, вот эталон.
У меня было два умы о публикации этого, потому что другое очевидное объяснение заключается в том, что я сделал какую-то смешную, глупую ошибку где-то, и я собираюсь в конечном итоге с яйцом на лице, но, о, какого черта.
$array = array( 'random' => 1, 'pewpew' => 2, 'temp' => 5, 'xoxo' => 3, 'qweqweqe' => 4, ); $fields = array('random', 'xoxo', 'temp'); // Let's not print anything just yet, maybe that's what screwing the timer? $results = ''; $duh = 0; for ($cycle = 0; $cycle < 10; $cycle++) { // Add some more elements to $array. for ($i = 0; $i < 10000; $i++) { $k = uniqid(); $array[$k] = 42; } $start = explode(' ', microtime()); // WTF? Do more cycles to average the timing. for ($j = 0; $j < 10; $j++) { // 0 or 1 to switch if (1) { // INTERPRETED ANSWER $answer = array(); foreach($fields as $fld) // N-sized cycle if (isset($array[$fld])) // Cost M $answer[$fld] = // Assignment is N*1/2 $array[$fld]; // Getting value is another M } else { // FUNCTION ANSWER $answer = array_replace( array_fill_keys($fields, false), // array_combine($fields, $fields), array_intersect_key($array, # Keys in array, without order array_flip($fields))); } // USE $answer so to avoid premature optimization? // You can't be that clever. $duh += strlen(serialize($answer)); } $stop = explode(' ', microtime()); // An error in timing? Check via a stupid roundabout. $int = $stop[1]-$start[1]+1; $int += ($stop[0]-$start[0]); $int -= 1; $elapsed = number_format($int * 1000000, 2); $results .= "".(5000*$cycle)." = $elapsed us.\n"; } // I need to get in result: $wanted = array( 'random' => 1, 'xoxo' => 3, 'temp' => 5, ); // DID we get the right answer? print "Wanted:\n"; print_r($wanted); print "Gotten:\n"; print_r($answer); print "Results: $results\n$duh -- count of array is " . count($array); // And yet I have always the same realtime, name of a dog, how can that be? // I must be doing something REALLY REALLY wrong somewhere.
Простой способ:
$array = array( 'random' => 1, 'pewpew' => 2, 'temp' => 5, 'xoxo' => 3, 'qweqweqe' => 4, ); $fields = array('random', 'xoxo', 'temp'); $output = array(); foreach ($fields as $value) if(isset($array[$value])) $output[$value]=$array[$value];
Это решение, которое также обрабатывает случай, когда некоторые $fields
не присутствуют в виде ключей в $array
:
$flip = array_flip($fields); $result = array_intersect_key(array_replace($flip, $array), array_intersect_key($flip, $array));
Если известно, что все $fields
присутствуют как ключи в $array
это более простое решение:
$flip = array_flip($fields); $result = array_intersect_key(array_replace($flip, $array), $flip);
который можно записать как однострочный:
$result = array_intersect_key(array_replace($flip=array_flip($fields), $array), $flip);
Если некоторые $fields
не являются ключами из $array
, но $array
содержит counts, так что имеет смысл вернуть 0
счет для отсутствующих ключей, мы можем заменить flip()
на array_fill_keys($fields, 0)
:
$result = array_intersect_key(array_replace($fill=array_fill_keys($fields, 0), $array), $fill);
к которому мы можем применить array_filter()
чтобы отфильтровать 0
с, если это необходимо. Заменяя 0
на false
или null
мы можем отмечать и обрабатывать отсутствие ключа в $array
когда значения не считаются.
Печально то, что эти решения, как и все остальные на этой странице, должны работать через все ключи $array
, в то время как любой явный цикл будет на $fields
. В настоящее время кажется, что когда count($array)
намного больше, чем count($fields)
решение на основе массива не существует так быстро, как явный цикл (поскольку они явно конструируют результат в функциях обратного вызова, Я рассматриваю array_walk()
и array_reduce()
как явные петли здесь).
Проблема в том, что ни одна из доступных функций array_
разрушает связь между ключами и значениями, и поскольку мы хотели бы зациклиться на $fields
или, вернее, перевернутом массиве, также сохранить свой порядок сортировки, сохраняя при этом значения $array
, нам не повезло.
Функция PHP называется array_diff_key .
Образец кода:
$array = array( 'random' => 1, 'pewpew' => 2, 'temp' => 5, 'xoxo' => 3, 'qweqweqe' => 4 ); $fields = array('random', 'xoxo', 'temp'); $result = array_diff_key($fields, $array);
Это даст желаемый результат.
Демо: http://shaquin.tk/experiments/array1.php
EDIT: если $fields
может содержать значение, которое не является ключом в $array
, используйте этот код:
$result = array_diff_key($fields, $array); $result = array_intersect_key(array_flip($fields), $array); $result = array_flip(array_diff(array_keys($result), $array)); $result = array_replace($result, $array); $result = array_flip(array_intersect(array_flip($result), $fields));
Возможно, это будет возможно немного оптимизировать, но оно работает!
Примечание. Я не могу ссылаться на пример, поскольку у моего (размещенного) сайта нет> = PHP 5.3, однако я могу ссылаться на аналогичный: http://shaquin.tk/experiments/array2.php .
пытаться:
$result=array(); reset($fields); while(list($key,$value)=each($fields)) { if(isset($array[$value])) $result[$value]=$array[$value]; }
в$result=array(); reset($fields); while(list($key,$value)=each($fields)) { if(isset($array[$value])) $result[$value]=$array[$value]; }
Это будет работать и сохранить порядок для вас:
$fields = array_flip($fields); array_merge($fields,array_intersect_key($array, $fields)); $fields = array_keys($fields);
заметьте, вы могли бы просто вызвать array_flip дважды, но выше показалось немного «более чистым».