Switch two items in associative array

后端 未结 17 1868
自闭症患者
自闭症患者 2021-02-05 12:53

Example:

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


        
相关标签:
17条回答
  • 2021-02-05 13:09

    There is no easy way to do this. This sounds like a slight design-logic error on your part which has lead you to try to do this when there is a better way to do whatever it is you are wanting to do. Can you tell us why you want to do this?

    You say that I know the keys and values of the elements I want to switch which makes me think that what you really want is a sorting function since you can easily access the proper elements anytime you want as they are.

    $value = $array[$key];
    

    If that is the case then I would use sort(), ksort() or one of the many other sorting functions to get the array how you want. You can even use usort() to Sort an array by values using a user-defined comparison function.

    Other than that you can use array_replace() if you ever need to swap values or keys.

    0 讨论(0)
  • 2021-02-05 13:11

    Here are two solutions. The first is longer, but doesn't create a temporary array, so it saves memory. The second probably runs faster, but uses more memory:

    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;
    }
    
    0 讨论(0)
  • 2021-02-05 13:13

    Not entirely sure if this was mentioned, but, the reason this is tricky is because it's non-indexed.

    Let's take:

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

    Get the keys:

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

    Get the values:

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

    Now you've got 2 arrays that are numerical. Swap the indices of the ones you want to swap, then read the other array back in in the order of the modified numerical array. Let's say we want to swap 'fruit' and '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
    )
    

    Now, you can swap back the array:

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

    Now, you can build an array by going through the oringal array in the 'order' of the rearranged keys.

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

    I haven't tested this - but this is what I'd expect. Does this at least provide any kind of help? Good luck :)

    You could put this into a function $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;
        }
    }
    ?>
    

    WARNING: Please test and debug this before just using it - no testing has been done at all.

    0 讨论(0)
  • 2021-02-05 13:13

    Well it's just a key sorting problem. We can use uksort for this purpose. It needs a key comparison function and we only need to know that it should return 0 to leave keys position untouched and something other than 0 to move key up or down.

    Notice that it will only work if your keys you want to swap are next to each other.

    <?php
    
    $arr = array(
      'apple'      => 'sweet',
      'grapefruit' => 'bitter',
      'pear'       => 'tasty',
      'banana'     => 'yellow'
    );
    
    uksort(
        $arr,
        function ($k1, $k2) {
            if ($k1 == 'grapefruit' && $k2 == 'pear') return 1;
            else return 0;
        }
    );
    
    var_dump($arr);
    
    0 讨论(0)
  • 2021-02-05 13:15

    Just a little shorter and less complicated than the solution of arcaneerudite:

    <?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);
    ?>
    

    Tested and works fine

    0 讨论(0)
  • 2021-02-05 13:18

    Classical associative array doesn't define or guarantee sequence of elements in any way. There is plain array/vector for that. If you use associative array you are assumed to need random access but not sequential. For me you are using assoc array for task it is not made for.

    0 讨论(0)
提交回复
热议问题