在关联数组中切换两个项目

时间:2010-03-15 15:37:08

标签: php arrays

示例:

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

我想切换葡萄柚和梨的位置,所以阵列将成为

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

我知道要切换的元素的键和值,是否有一种简单的方法可以做到这一点?或者它需要一个循环+创建一个新数组?

由于

17 个答案:

答案 0 :(得分:18)

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

经过测试并且工作正常

答案 1 :(得分:4)

这是我的交换功能版本:

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

答案 2 :(得分:2)

如果数组来自db,请添加sort_order字段,以便始终确保元素在数组中的顺序。

答案 3 :(得分:1)

这可能是也可能不是一个选项,具体取决于您的特定用例,但如果使用适当的键在使用数据填充数据之前使用空值初始化数组,则可以按任何顺序设置值和原始键订单将被维护。因此,您可以避免交换元素,而不是交换元素:

$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
)

答案 4 :(得分:1)

不完全确定是否提到了这一点,但是,这很棘手的原因是因为它没有索引。

我们来看看:

$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个数字数组。交换要交换的索引,然后按修改后的数值数组的顺序读回另一个数组。假设我们要交换'fruit'和'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
)

现在,您可以通过重新排列键的“顺序”中的oringal数组来构建数组。

$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;
    }
}
?>

警告:请在使用之前对其进行测试和调试 - 根本没有进行任何测试。

答案 5 :(得分:0)

嗯,这只是一个关键的排序问题。为此,我们可以使用uksort。它需要一个键比较功能,我们只需要知道应该返回0即可保持键位置不变,而返回0则可以返回上下键。

请注意,仅当您要交换的密钥彼此相邻时,此方法才有效。

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

答案 6 :(得分:0)

没有简单的方法,只是循环或新的数组定义。

答案 7 :(得分:0)

我也将分享我的简短版本,它适用于数字数组和关联数组。

array array_swap ( array $array , mixed $key1 , mixed $key2 [, bool $preserve_keys = FALSE [, bool $strict = FALSE ]] )

返回交换了两个元素的新数组。如果指定,它将保留原始密钥。如果找不到密钥,则返回FALSE。

function array_swap(array $array, $key1, $key2, $preserve_keys = false, $strict = false) {
    $keys = array_keys($array);
    if(!array_key_exists($key1, $array) || !array_key_exists($key2, $array)) return false;
    if(($index1 = array_search($key1, $keys, $strict)) === false) return false;
    if(($index2 = array_search($key2, $keys, $strict)) === false) return false;
    if(!$preserve_keys) list($keys[$index1], $keys[$index2]) = array($key2, $key1);
    list($array[$key1], $array[$key2]) = array($array[$key2], $array[$key1]);
    return array_combine($keys, array_values($array));
}

例如:

$arr = array_swap($arr, 'grapefruit', 'pear');

答案 8 :(得分:0)

function arr_swap_keys(array &$arr, $key1, $key2, $f_swap_vals=false) {
   // if f_swap_vals is false, then
   // swap only the keys, keeping the original values in their original place
   // ( i.e. do not preserve the key value correspondence )
   // i.e. if arr is (originally)
   // [ 'dog' => 'alpha', 'cat' => 'beta', 'horse' => 'gamma' ]
   // then calling this on arr with, e.g. key1 = 'cat', and key2 = 'horse'
   // will result in arr becoming: 
   // [ 'dog' => 'alpha', 'horse' => 'beta', 'cat' => 'gamma' ]
   // 
   // if f_swap_vals is true, then preserve the key value correspondence
   // i.e. in the above example, arr will become:
   // [ 'dog' => 'alpha', 'horse' => 'gamma', 'cat' => 'beta' ]
   // 
   // 

   $arr_vals = array_values($arr); // is a (numerical) index to value mapping
   $arr_keys = array_keys($arr);   // is a (numerical) index to key mapping
   $arr_key2idx = array_flip($arr_keys);
   $idx1 = $arr_key2idx[$key1];
   $idx2 = $arr_key2idx[$key2];
   swap($arr_keys[$idx1], $arr_keys[$idx2]);
   if ( $f_swap_vals ) {
      swap($arr_vals[$idx1], $arr_vals[$idx2]);
   }
   $arr = array_combine($arr_keys, $arr_vals);
}

function swap(&$a, &$b) {
   $t = $a;
   $a = $b;
   $b = $t;
}

答案 9 :(得分:0)

有一种简单的方法:

$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'
)

答案 10 :(得分:0)

fwiw这是一个交换两个相邻项的函数,用于在没有foreach()的关联数组中实现moveUp()或moveDown()

/**
 * @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)); 
}

答案 11 :(得分:0)

这是两个解决方案。第一个是更长的,但不创建临时数组,因此它节省了内存。第二个可能运行得更快,但使用更多内存:

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;
}

答案 12 :(得分:0)

没有简单的方法可以做到这一点。这听起来像是一个轻微的设计逻辑错误,当你有更好的方法去做你想做的事情时,这会导致你尝试这样做。你能告诉我们你为什么要这样做吗?

你说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()

答案 13 :(得分:0)

是的我同意Lex,如果你使用关联数组来保存数据,为什么不使用你的逻辑句柄来访问它们,而不是取决于它们在数组中的排列方式。

如果您真的想确保它们的顺序正确,请尝试创建水果对象,然后将它们放入正常的数组中。

答案 14 :(得分:0)

经典关联数组不以任何方式定义或保证元素序列。有平原数组/向量。如果使用关联数组,则假定您需要随机访问但不需要顺序访问。对我来说,你正在使用assoc数组来完成它的任务。

答案 15 :(得分:-1)

我写了一个更通用的函数,记住了这个问题。

  1. 包含已知密钥的数组
  2. 指定第二个数组中键的顺序($ order数组键表示键位置)
  3. 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 )
    

    我希望这对某人有用/有用

答案 16 :(得分:-2)

php中的数组是有序地图。

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

并不意味着第一个元素是'apple'=&gt;'sweet'而最后一个 - 'banana'=&gt;'yellow'只是因为你先把'apple'和'banana'放在最后。实际上,'apple'=&gt;'sweet'将是第一个和 'banana'=&gt;'yellow'将是第二个,因为按字母顺序升序排序。