【问题标题】:Move an array element to a new index in PHP将数组元素移动到 PHP 中的新索引
【发布时间】:2012-09-27 14:50:03
【问题描述】:

我正在寻找一个简单的函数来将数组元素移动到数组中的新位置并重新排序索引,以便序列中没有间隙。它不需要使用关联数组。有人对这个有想法吗?

$a = array(
      0 => 'a',
      1 => 'c',
      2 => 'd',
      3 => 'b',
      4 => 'e',
);
print_r(moveElement(3,1))
//should output 
    [ 0 => 'a',
      1 => 'b',
      2 => 'c',
      3 => 'd',
      4 => 'e' ]

【问题讨论】:

  • 一些具有预期结果的代码会有所帮助...

标签: php arrays


【解决方案1】:

如评论,2x array_splice,甚至不需要重新编号:

$array = [
    0 => 'a', 
    1 => 'c', 
    2 => 'd', 
    3 => 'b', 
    4 => 'e',
];

function moveElement(&$array, $a, $b) {
    $out = array_splice($array, $a, 1);
    array_splice($array, $b, 0, $out);
}

moveElement($array, 3, 1);

结果:

[
    0 => 'a',
    1 => 'b',
    2 => 'c',
    3 => 'd',
    4 => 'e',
];

【讨论】:

  • 是的,这是一个不错且简单的解决方案,但它仅在旧索引大于新索引时才有效。这是另一个解决方案:link
  • @quarky:不,如果新索引大于旧索引,它也会起作用。如果两者相同,也是如此。
  • 但是如果你的目的地在源之后,它可能不会把它放在你预测的地方,因为在第一步之后数组会变短。如果移动到最后,你不想使用 size-1,你想要 size-2
  • @GarrGodfrey:老实说,我从未见过可以很好地进行预测的代码。不过感谢您的反馈。
  • 澄清$a$fromIndex$b$toIndex
【解决方案2】:

很多很好的答案。这是一个基于@RubbelDeCatc 的答案的简单方法。它的美妙之处在于您只需要知道数组键,而不是它的当前位置(重新定位之前)。

/**
 * Reposition an array element by its key.
 *
 * @param array      $array The array being reordered.
 * @param string|int $key They key of the element you want to reposition.
 * @param int        $order The position in the array you want to move the element to. (0 is first)
 *
 * @throws \Exception
 */
function repositionArrayElement(array &$array, $key, int $order): void
{
    if(($a = array_search($key, array_keys($array))) === false){
        throw new \Exception("The {$key} cannot be found in the given array.");
    }
    $p1 = array_splice($array, $a, 1);
    $p2 = array_splice($array, 0, $order);
    $array = array_merge($p2, $p1, $array);
}

直接使用:

$fruits = [
    'bananas'=>'12', 
    'apples'=>'23',
    'tomatoes'=>'21', 
    'nuts'=>'22',
    'foo'=>'a',
    'bar'=>'b'
];

repositionArrayElement($fruits, "foo", 1);

var_export($fruits);

/** Returns
array (
  'bananas' => '12',
  'foo' => 'a', <--  Now moved to position #1
  'apples' => '23',
  'tomatoes' => '21',
  'nuts' => '22',
  'bar' => 'b',
)
**/

也适用于数值数组:

$colours = ["green", "blue", "red"];

repositionArrayElement($colours, 2, 0);

var_export($colours);

/** Returns
array (
  0 => 'red', <-- Now moved to position #0
  1 => 'green',
  2 => 'blue',
)
*/

Demo

【讨论】:

  • 这就像一个魅力,如此优雅
【解决方案3】:

PHP 中的数组不是 C 语言中的实际数组,而是关联数组。 但是将值从索引移动到另一个索引的方法很简单,并且与 C++ 中的相同:

复制该值以移动到一个临时缓冲区,翻译所有元素以粉碎源位置的空点,同时释放目标位置的一个点。 将备份值放在目标位置。

function moveElement ($a , $i , $j)
{
      $tmp =  $a[$i];
      if ($i > $j)
      {
           for ($k = $i; $k > $j; $k--) {
                $a[$k] = $a[$k-1]; 
           }        
      }
      else
      { 
           for ($k = $i; $k < $j; $k++) {
                $a[$k] = $a[$k+1];
           }
      }
      $a[$j] = $tmp;
      return $a;
}


$a = array(0, 1, 2, 3, 4, 5);
print_r($a);

$a = moveElement($a, 1, 4);
echo ('1 ->  4');
print_r($a);


$a = moveElement($a, 5, 0);
echo ('5 ->  0' );
print_r($a);

输出:

Array
(
    [0] => 0
    [1] => 1
    [2] => 2
    [3] => 3
    [4] => 4
    [5] => 5
)
1 ->  4Array
(
    [0] => 0
    [1] => 2
    [2] => 3
    [3] => 4
    [4] => 1
    [5] => 5
)
5 ->  0Array
(
    [0] => 5
    [1] => 0
    [2] => 2
    [3] => 3
    [4] => 4
    [5] => 1
)

您需要添加一些异常处理以获得完整的代码。

【讨论】:

    【解决方案4】:

    来自 hakre 的带有两个 array_splice 命令的解决方案不适用于命名数组。被移动元素的key会丢失。

    相反,您可以将数组拼接两次并合并部分。

    function moveElement(&$array, $a, $b) {
        $p1 = array_splice($array, $a, 1);
        $p2 = array_splice($array, 0, $b);
        $array = array_merge($p2,$p1,$array);
    }
    

    它是如何工作的:

    • 首先:从数组中移除/拼接元素
    • 二:在要插入元素的位置将数组拼接成两部分
    • 将三个部分合并在一起

    例子:

    $fruits = array(
        'bananas'=>'12', 
        'apples'=>'23',
        'tomatoes'=>'21', 
        'nuts'=>'22',
        'foo'=>'a',
        'bar'=>'b'
    );
    
    moveElement($fruits, 1, 3);
    
    // Result
    ['bananas'=>'12', 'tomatoes'=>'21', 'nuts'=>'22', 'apples'=>'23', 'foo'=>'a', 'bar'=>'b']
    

    【讨论】:

    • Apples 是索引 1,Tomato 是索引 3。在您的结果中,Tomato 现在是 1,Apples 现在是索引 4,而坚果是索引 3。那么这个解决方案到底如何?
    • 你必须从 0 开始计数。苹果在位置 1,它被移动到位置 3
    • 你交换 1, 3 。 之前:(1= Apples , 3 = 坚果) 你会得到 **After: 1 = Tomatoes 3 = Apples 。这不是交换,它只是将苹果移动到正确的索引 (3),但现在不是坚果为 1,而是西红柿为 1。
    【解决方案5】:

    可能是我错了,但是复制数组然后替换值不是更容易吗?

    function swap($input, $a, $b){
      $output = $input;
      $output[$a] = $input[$b];
      $output[$b] = $input[$a];
      return $output;
    }
    
    $array = ['a', 'c', 'b'];
    $array = swap($array, 1, 2);
    

    【讨论】:

    • 这样你只交换两个元素但是任务是移动
    【解决方案6】:

    你需要创建一个辅助变量。

    moveElement($a, $i,$j)
      {
      $k=$a[$i];
      $a[$i]=$a[$j];
      $a[$j]=$k;
      return $a;
      }
    

    【讨论】:

    • 这更像swapElements(),但不会移动
    • 否:c 将转到 3 而不是 2 像示例中那样。
    【解决方案7】:

    查看描述类似问题的this 线程。提供以下解决方案:

    /**
     * Move array element by index.  Only works with zero-based,
     * contiguously-indexed arrays
     *
     * @param array $array
     * @param integer $from Use NULL when you want to move the last element
     * @param integer $to   New index for moved element. Use NULL to push
     * 
     * @throws Exception
     * 
     * @return array Newly re-ordered array
     */
    function moveValueByIndex( array $array, $from=null, $to=null )
    {
      if ( null === $from )
      {
        $from = count( $array ) - 1;
      }
    
      if ( !isset( $array[$from] ) )
      {
        throw new Exception( "Offset $from does not exist" );
      }
    
      if ( array_keys( $array ) != range( 0, count( $array ) - 1 ) )
      {
        throw new Exception( "Invalid array keys" );
      }
    
      $value = $array[$from];
      unset( $array[$from] );
    
      if ( null === $to )
      {
        array_push( $array, $value );
      } else {
        $tail = array_splice( $array, $to );
        array_push( $array, $value );
        $array = array_merge( $array, $tail );
      }
    
      return $array;
    }
    

    【讨论】:

      【解决方案8】:

      保留键的函数:

      function moveElementInArray($array, $toMove, $targetIndex) {
          if (is_int($toMove)) {
              $tmp = array_splice($array, $toMove, 1);
              array_splice($array, $targetIndex, 0, $tmp);
              $output = $array;
          }
          elseif (is_string($toMove)) {
              $indexToMove = array_search($toMove, array_keys($array));
              $itemToMove = $array[$toMove];
              array_splice($array, $indexToMove, 1);
              $i = 0;
              $output = Array();
              foreach($array as $key => $item) {
                  if ($i == $targetIndex) {
                      $output[$toMove] = $itemToMove;
                  }
                  $output[$key] = $item;
                  $i++;
              }
          }
          return $output;
      }
      
      $arr1 = Array('a', 'b', 'c', 'd', 'e');
      $arr2 = Array('A' => 'a', 'B' => 'b', 'C' => 'c', 'D' => 'd', 'E' => 'e');
      
      print_r(moveElementInArray($arr1, 3, 1));
      print_r(moveElementInArray($arr2, 'D', 1));
      

      输出:

      Array
      (
          [0] => a
          [1] => d
          [2] => b
          [3] => c
          [4] => e
      )
      Array
      (
          [A] => a
          [D] => d
          [B] => b
          [C] => c
          [E] => e
      )
      

      【讨论】:

        【解决方案9】:

        基于a previous answer。如果您需要保存关联数组的键索引,可以是任意数字或字符串:

        function custom_splice(&$ar, $a, $b){
            $out = array_splice($ar, $a, 1);
            array_splice($ar, $b, 0, $out);
        }
        
        function moveElement(&$array, $a, $b) {
            $keys = array_keys($array);
        
            custom_splice($array, $a, $b);
            custom_splice($keys, $a, $b); 
        
            $array = array_combine($keys,$array);
        }
        
        $s = '{ 
        "21": "b", 
        "2": "2", 
        "3": "3", 
        "4": "4", 
        "6": "5", 
        "7": "6" 
        }';
        $e = json_decode($s,true);
        
        moveElement($e, 2, 0); 
        
        print_r($e);
        
        Array
        (
            [3] => 3
            [21] => b
            [2] => 2
            [4] => 4
            [6] => 5
            [7] => 6
        )
        

        Demo

        A previous answer 破坏数字索引 - 使它们从 0 开始。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-10-25
          • 2012-07-23
          相关资源
          最近更新 更多