交换关联数组中两个元素的位置

17

示例:

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

我想交换葡萄柚和梨的位置,这样数组就会变成

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

我知道要交换的元素的键和值,有没有一种简单的方法来做到这一点?还是需要循环+创建一个新数组?

谢谢

17个回答

19

这个解决方案比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,但如果一个索引存在而另一个不存在,它将会崩溃。 - Matthew
@Mathew:确实,但是在修复这个问题之后它会很好地达到预期的目的。 - Mike
+1,这似乎非常适合交换大数组的元素。对于小而简单的两个元素交换,我更喜欢直接解决方案!:] - trejder
@trejder:但是你的直接解决方案将无法保留键! - Legionar
+1 添加此行以修复崩溃: if (!isset($array[$key1]) || !isset($array[$key2])) {throw new InvalidArgumentException();} - YAMM

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
如果数组来自数据库,请添加一个sort_order字段,这样您就可以始终确定数组元素的顺序。

1

这可能取决于您特定的用例,但如果在填充数据之前使用适当的键初始化数组为 null 值,您可以以任何顺序设置值,并且原始键顺序将得到保留。因此,您可以避免交换元素而无需进行交换:

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

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
)

现在你有两个数值数组。交换你想要交换的索引,然后按照修改后的数值数组的顺序读取另一个数组。假设我们想要交换“水果”和“蔬菜”:

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

警告:在使用之前,请先测试和调试代码 - 目前还未进行任何测试。


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

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

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

0

这只是一个关键字排序问题。我们可以使用uksort来解决这个问题。它需要一个关键字比较函数,我们只需要知道它应该返回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);

0

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

你说 我知道我想要交换的元素的键和值,这让我想到你真正想要的是一个排序函数,因为你可以随时轻松访问正确的元素。

$value = $array[$key];

如果是这种情况,我会使用sort(), ksort()或其他许多排序函数来获取你想要的数组。你甚至可以使用usort()通过使用用户定义的比较函数对值进行排序。

除此之外,如果你需要交换值或键,你还可以使用array_replace()


1
当有人提出问题时,不要做任何假设。 - JG Estiot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接