Переключение двух элементов в ассоциативном массиве

Пример:

$arr = array( 'apple' => 'sweet', 'grapefruit' => 'bitter', 'pear' => 'tasty', 'banana' => 'yellow' ); 

Я хочу переключить позиции грейпфрута и груши, поэтому массив станет

 $arr = array( 'apple' => 'sweet', 'pear' => 'tasty', 'grapefruit' => 'bitter', 'banana' => 'yellow' ) 

Я знаю ключи и значения элементов, которые я хочу переключить, есть ли простой способ сделать это? Или потребуется цикл + создание нового массива?

благодаря

Нет простого способа, просто цикла или определения нового массива.

Просто немного короче и менее сложно, чем решение арканерудита:

 <?php if(!function_exists('array_swap_assoc')) { function array_swap_assoc($key1, $key2, $array) { $newArray = array (); foreach ($array as $key => $value) { if ($key == $key1) { $newArray[$key2] = $array[$key2]; } elseif ($key == $key2) { $newArray[$key1] = $array[$key1]; } else { $newArray[$key] = $value; } } return $newArray; } } $array = $arrOrig = array( 'fruit' => 'pear', 'veg' => 'cucumber', 'tuber' => 'potato', 'meat' => 'ham' ); $newArray = array_swap_assoc('veg', 'tuber', $array); var_dump($array, $newArray); ?> 

Протестировано и отлично работает

Вот моя версия функции свопинга:

 function array_swap_assoc(&$array,$k1,$k2) { if($k1 === $k2) return; // Nothing to do $keys = array_keys($array); $p1 = array_search($k1, $keys); if($p1 === FALSE) return; // Sanity check...keys must exist $p2 = array_search($k2, $keys); if($p2 === FALSE) return; $keys[$p1] = $k2; // Swap the keys $keys[$p2] = $k1; $values = array_values($array); // Swap the values list($values[$p1],$values[$p2]) = array($values[$p2],$values[$p1]); $array = array_combine($keys, $values); } 

если массив поступает из db, добавьте поле sort_order, чтобы вы всегда могли быть уверены, в каком порядке элементы находятся в массиве.

Нет простого способа сделать это. Это звучит как небольшая логическая ошибка с вашей стороны, которая заставила вас попытаться сделать это, когда есть лучший способ сделать то, что вы хотите сделать. Можете ли вы рассказать нам, почему вы хотите это сделать?

Вы говорите, что I know the keys and values of the elements I want to switch что заставляет меня думать, что то, что вы действительно хотите, – это функция сортировки, так как вы можете легко получить доступ к соответствующим элементам в любое время, когда захотите.

 $value = $array[$key]; 

Если это так, то я бы использовал sort () , ksort () или одну из многих других функций сортировки, чтобы получить массив, как вы хотите. Вы можете даже использовать usort () для Sort an array by values using a user-defined comparison function .

Помимо этого вы можете использовать array_replace (), если вам когда-либо понадобится менять значения или ключи.

Это может быть или не быть вариантом в зависимости от вашего конкретного варианта использования, но если вы инициализируете свой массив нулевыми значениями с соответствующими ключами, прежде чем заполнять его данными, вы можете установить значения в любом порядке, а исходный порядок клавиш будет поддерживаться. Поэтому вместо замены элементов вы можете предотвратить необходимость их полной замены:

 $arr = array('apple' => null, 'pear' => null, 'grapefruit' => null, 'banana' => null); 

 $arr['apple'] = 'sweet'; $arr['grapefruit'] = 'bitter'; // set grapefruit before setting pear $arr['pear'] = 'tasty'; $arr['banana'] = 'yellow'; print_r($arr); >>> Array ( [apple] => sweet [pear] => tasty [grapefruit] => bitter [banana] => yellow ) 

Не совсем уверен, что это было упомянуто, но причина в том, что это сложно, потому что он не индексирован.

Давайте:

 $arrOrig = array( 'fruit'=>'pear', 'veg'=>'cucumber', 'tuber'=>'potato' ); 

Получить ключи:

 $arrKeys = array_keys($arrOrig); print_r($arrKeys); Array( [0]=>fruit [1]=>veg [2]=>tuber ) 

Получить значения:

 $arrVals = array_values($arrOrig); print_r($arrVals); Array( [0]=>pear [1]=>cucumber [2]=>potato ) 

Теперь у вас есть 2 массива, которые являются численными. Перемените индексы тех, которые вы хотите поменять местами, затем перечитайте другой массив в порядке модифицированного числового массива. Предположим, мы хотим поменять «фрукты» и «veg»:

 $arrKeysFlipped = array_flip($arrKeys); print_r($arrKeysFlipped); Array ( [fruit]=>0 [veg]=>1 [tuber]=>2 ) $indexFruit = $arrKeysFlipped['fruit']; $indexVeg = $arrKeysFlipped['veg']; $arrKeysFlipped['veg'] = $indexFruit; $arrKeysFlipped['fruit'] = $indexVeg; print_r($arrKeysFlipped); Array ( [fruit]=>1 [veg]=>0 [tuber]=>2 ) 

Теперь вы можете поменять массив:

 $arrKeys = array_flip($arrKeysFlipped); print_r($arrKeys); Array ( [0]=>veg [1]=>fruit [2]=>tuber ) 

Теперь вы можете построить массив, пройдя массив оргиналов в «порядке» перестроенных ключей.

 $arrNew = array (); foreach($arrKeys as $index=>$key) { $arrNew[$key] = $arrOrig[$key]; } print_r($arrNew); Array ( [veg]=>cucumber [fruit]=>pear [tuber]=>potato ) 

Я не тестировал это, но это то, чего я ожидал. Это, по крайней мере, предоставляет какую-либо помощь? Удачи 🙂

Вы можете поместить это в функцию $arrNew = array_swap_assoc($key1,$key2,$arrOld);

 <?php if(!function_exists('array_swap_assoc')) { function array_swap_assoc($key1='',$key2='',$arrOld=array()) { $arrNew = array (); if(is_array($arrOld) && count($arrOld) > 0) { $arrKeys = array_keys($arrOld); $arrFlip = array_flip($arrKeys); $indexA = $arrFlip[$key1]; $indexB = $arrFlip[$key2]; $arrFlip[$key1]=$indexB; $arrFlip[$key2]=$indexA; $arrKeys = array_flip($arrFlip); foreach($arrKeys as $index=>$key) { $arrNew[$key] = $arrOld[$key]; } } else { $arrNew = $arrOld; } return $arrNew; } } ?> 

ПРЕДУПРЕЖДЕНИЕ. Протестируйте и отлаживайте это, прежде чем использовать его – никаких проверок не было.

Классический ассоциативный массив никак не определяет или не гарантирует последовательность элементов. Для этого есть простой массив / вектор. Если вы используете ассоциативный массив, предполагается, что вам нужен произвольный доступ, но не последовательный. Для меня вы используете массив-помощник для задачи, для которой он не предназначен.

да, я согласен с Лексом, если вы используете ассоциативный массив для хранения данных, почему бы не использовать ваш логический дескриптор, к какому пути они обращаются, а не в зависимости от того, как они расположены в массиве.

Если вы действительно хотели убедиться, что они были в правильном порядке, пытаясь создать плодовые объекты, а затем помещать их в нормальный массив.

Вот два решения. Первый длиннее, но не создает временный массив, поэтому он сохраняет память. Второй, вероятно, работает быстрее, но использует больше памяти:

 function swap1(array &$a, $key1, $key2) { if (!array_key_exists($key1, $a) || !array_key_exists($key2, $a) || $key1 == $key2) return false; $after = array(); while (list($key, $val) = each($a)) { if ($key1 == $key) { break; } else if ($key2 == $key) { $tmp = $key1; $key1 = $key2; $key2 = $tmp; break; } } $val1 = $a[$key1]; $val2 = $a[$key2]; while (list($key, $val) = each($a)) { if ($key == $key2) $after[$key1] = $val1; else $after[$key] = $val; unset($a[$key]); } unset($a[$key1]); $a[$key2] = $val2; while (list($key, $val) = each($after)) { $a[$key] = $val; unset($after[$key]); } return true; } function swap2(array &$a, $key1, $key2) { if (!array_key_exists($key1, $a) || !array_key_exists($key2, $a) || $key1 == $key2) return false; $swapped = array(); foreach ($a as $key => $val) { if ($key == $key1) $swapped[$key2] = $a[$key2]; else if ($key == $key2) $swapped[$key1] = $a[$key1]; else $swapped[$key] = $val; } $a = $swapped; return true; } с function swap1(array &$a, $key1, $key2) { if (!array_key_exists($key1, $a) || !array_key_exists($key2, $a) || $key1 == $key2) return false; $after = array(); while (list($key, $val) = each($a)) { if ($key1 == $key) { break; } else if ($key2 == $key) { $tmp = $key1; $key1 = $key2; $key2 = $tmp; break; } } $val1 = $a[$key1]; $val2 = $a[$key2]; while (list($key, $val) = each($a)) { if ($key == $key2) $after[$key1] = $val1; else $after[$key] = $val; unset($a[$key]); } unset($a[$key1]); $a[$key2] = $val2; while (list($key, $val) = each($after)) { $a[$key] = $val; unset($after[$key]); } return true; } function swap2(array &$a, $key1, $key2) { if (!array_key_exists($key1, $a) || !array_key_exists($key2, $a) || $key1 == $key2) return false; $swapped = array(); foreach ($a as $key => $val) { if ($key == $key1) $swapped[$key2] = $a[$key2]; else if ($key == $key2) $swapped[$key1] = $a[$key1]; else $swapped[$key] = $val; } $a = $swapped; return true; } с function swap1(array &$a, $key1, $key2) { if (!array_key_exists($key1, $a) || !array_key_exists($key2, $a) || $key1 == $key2) return false; $after = array(); while (list($key, $val) = each($a)) { if ($key1 == $key) { break; } else if ($key2 == $key) { $tmp = $key1; $key1 = $key2; $key2 = $tmp; break; } } $val1 = $a[$key1]; $val2 = $a[$key2]; while (list($key, $val) = each($a)) { if ($key == $key2) $after[$key1] = $val1; else $after[$key] = $val; unset($a[$key]); } unset($a[$key1]); $a[$key2] = $val2; while (list($key, $val) = each($after)) { $a[$key] = $val; unset($after[$key]); } return true; } function swap2(array &$a, $key1, $key2) { if (!array_key_exists($key1, $a) || !array_key_exists($key2, $a) || $key1 == $key2) return false; $swapped = array(); foreach ($a as $key => $val) { if ($key == $key1) $swapped[$key2] = $a[$key2]; else if ($key == $key2) $swapped[$key1] = $a[$key1]; else $swapped[$key] = $val; } $a = $swapped; return true; } с function swap1(array &$a, $key1, $key2) { if (!array_key_exists($key1, $a) || !array_key_exists($key2, $a) || $key1 == $key2) return false; $after = array(); while (list($key, $val) = each($a)) { if ($key1 == $key) { break; } else if ($key2 == $key) { $tmp = $key1; $key1 = $key2; $key2 = $tmp; break; } } $val1 = $a[$key1]; $val2 = $a[$key2]; while (list($key, $val) = each($a)) { if ($key == $key2) $after[$key1] = $val1; else $after[$key] = $val; unset($a[$key]); } unset($a[$key1]); $a[$key2] = $val2; while (list($key, $val) = each($after)) { $a[$key] = $val; unset($after[$key]); } return true; } function swap2(array &$a, $key1, $key2) { if (!array_key_exists($key1, $a) || !array_key_exists($key2, $a) || $key1 == $key2) return false; $swapped = array(); foreach ($a as $key => $val) { if ($key == $key1) $swapped[$key2] = $a[$key2]; else if ($key == $key2) $swapped[$key1] = $a[$key1]; else $swapped[$key] = $val; } $a = $swapped; return true; } 

fwiw здесь – функция для обмена двумя смежными элементами для реализации moveUp () или moveDown () в ассоциативном массиве без foreach ()

 /** * @param array $array to modify * @param string $key key to move * @param int $direction +1 for down | -1 for up * @return $array */ protected function moveInArray($array, $key, $direction = 1) { if (empty($array)) { return $array; } $keys = array_keys($array); $index = array_search($key, $keys); if ($index === false) { return $array; // not found } if ($direction < 0) { $index--; } if ($index < 0 || $index >= count($array) - 1) { return $array; // at the edge: cannot move } $a = $keys[$index]; $b = $keys[$index + 1]; $result = array_slice($array, 0, $index, true); $result[$b] = $array[$b]; $result[$a] = $array[$a]; return array_merge($result, array_slice($array, $index + 2, null, true)); } 

Существует простой способ:

 $sourceArray = array( 'apple' => 'sweet', 'grapefruit' => 'bitter', 'pear' => 'tasty', 'banana' => 'yellow' ); // set new order $orderArray = array( 'apple' => '', //this values would be replaced 'pear' => '', 'grapefruit' => '', //it is not necessary to touch all elemets that will remains the same ); $result = array_replace($orderArray, $sourceArray); print_r($result); 

и вы получаете:

 $result = array( 'apple' => 'sweet', 'pear' => 'tasty', 'grapefruit' => 'bitter', 'banana' => 'yellow' ) 

Я написал функцию с более общей целью, имея в виду эту проблему.

  1. массив с известными ключами
  2. указать порядок ключей во втором массиве (ключи $ order array указывают положение ключа)

function order_array ($ array, $ order) {

  foreach (array_keys($array) as $k => $v) { $keys[++$k] = $v; } for ($i = 1; $i <= count($array); $i++) { if (isset($order[$i])) { unset($keys[array_search($order[$i], $keys)]); } if ($i === count($array)) { array_push($keys, $order[$i]); } else { array_splice($keys, $i-1, 0, $order[$i]); } } } foreach ($keys as $key) { $result[$key] = $array[$key]; } return $result; } else { return false; } } $order = array(1 => 'item3', 2 => 'item5'); $array = array("item1" => 'val1', "item2" => 'val2', "item3" => 'val3', "item4" => 'val4', "item5" => 'val5'); print_r($array); -> Array ( [item1] => val1 [item2] => val2 [item3] => val3 [item4] => val4 [item5] => val5 ) print_r(order_array($array, $order)); -> Array ( [item3] => val3 [item5] => val5 [item1] => val1 [item2] => val2 [item4] => val4 ) 

Я надеюсь, что это важно / полезно для кого-то

Массивы в php – это упорядоченные карты.

 $arr = array('apple'=>'sweet','grapefruit'=>'bitter',' pear'=>'tasty','banana'=>'yellow'); 

не означает, что первым элементом является «яблоко» => «сладкое», а последнее – «банана» => «желтое» только потому, что вы положили «яблоко» первым и «банан» последним. На самом деле, «яблоко» => «сладкое» будет первым, а «банан» => «желтый» будет вторым из-за алфавитного возрастающего порядка сортировки.