【问题标题】:Insert elements at an array position even if the array is empty or position doesn't exist即使数组为空或位置不存在,在数组位置插入元素
【发布时间】:2015-06-09 14:35:46
【问题描述】:

我尝试使用此处所述的array_splice 策略 Insert new item in array on any position in PHP

但它不起作用,因为数组为空或键不存在。所以我尝试检查是否先设置密钥然后创建它。但它仍然不起作用。

例如,如果数组在第一次调用中为空,并且我想在索引 3 处插入元素,并且我在 array_splice 之前创建位置 3,则从位置 0 插入元素。如果我不这样做,也会发生同样的情况在使用array_splice 之前不要检查。如果数组为空,则插入失败

function array_insert($array,$input,$index){
    if(!isset($array[$index])) $array[$index] = 0;
    array_splice($array,$index,0,$input);

    return $array;
}

所以下面的调用

array_insert(array(),array(36,37),3);

生成这个

array(1) { [3]=> int(0) } //var_dump before splice, after isset
array(3) { [0]=> int(0) [1]=> string(2) "36" [2]=> string(2) "37" } //var_dump  after splice

我错过了什么?!

@编辑 预期结果是: 如果我在空数组中的位置 3 处插入 array('a','b','c'),则结果数组应该允许我通过键 3 访问 'a',通过 4 等访问'b'。不知道是什么更好的是,空值来填补空白或关联键。

@edit2

insert(array(),array(1,2),3);

数组(2) { [3]=> int(1) [4]=> int(2) }

$a = array(); $a[2] = 3; insert($a,array(1,2),1);

array(3) { 1=> int(1) [2]=> int(2) [3] => int(3) }

insert(array(1,2),array(4,5),1);

array(4) { [0]=> int(1) 1=> int(4) [2] => int(5) [3] => int(2) }

在性能方面,顺便说一句更好的选择是什么?

【问题讨论】:

  • 我们需要一个例子。预期的结果是什么?我很少单独相信描述......它们很容易被误解。
  • 审查。请不要(不仅仅是一个)描述。结果。你知道,这让我有机会验证我对描述的理解是否正确。
  • 你真的需要这些空隙吗?由于所有 PHP 数组实际上是映射/字典,因此您可以轻松地使用$array[3],而无需设置$array[0]$array[1]$array[2]
  • PHP 中没有按照您描述的方式运行的现有函数,即 插入键,同时在冲突时向前推动其他键,而无需彻底重新编号项目。 您需要编写您自己的实现可以完成所有这些。
  • 我认为您遇到了困难,因为您的要求非常奇怪,这可能意味着您对问题的建模效率低下。如果您真的需要以这种方式运行的东西,我建议您编写一个自定义数据结构(一个对客户端代码隐藏详细信息的类)以及验证不同情况的测试。您将不得不在代码中手动操作索引和/或在底层使用简单数组以外的其他东西。

标签: php arrays array-splice


【解决方案1】:

我认为这可以满足您的要求,并且我已经包含了测试用例,以便您自己判断。

class ShiftingArray implements ArrayAccess
{
    private $values;

    public function __construct ($initial_values = array ())
    {
        $this->values = $initial_values;
    }

    public function get_values ()
    {
        return $this->values;
    }

    public function insert ($new_values, $offset)
    {
        if (!is_array ($new_values))
        {
            $new_values = array ($new_values);
        }

        foreach ($new_values as $value)
        {
            $this->insert_single ($offset, $value);
            $offset++;
        }
    }

    private function insert_single ($index, $value)
    {
        if (isset ($this->values[$index]))
        {
            $this->insert_single ($index + 1, $this->values[$index]);
        }
        $this->values[$index] = $value;
    }

    /**
    *   The following methods allow you to use an instance of ShiftingArray
    *   like a normal array, e.g.
    *
    *   $array = new ShiftingArray ();
    *   $array->insert (array (1,2,3), 4);
    *   echo $array[5]; //  prints 2
    */

    /*  boolean ArrayAccess::offsetExists (mixed $offset) */
    public function offsetExists ($offset)
    {
        return isset ($this->values [$offset]);
    }

    /*  mixed ArrayAccess::offsetGet (mixed $offset) */
    public function offsetGet ($offset)
    {
        return isset ($this->values [$offset]) ? $this->values[$offset] : null;
    }

    /*  ArrayAccess::offsetSet (mixed $offset, mixed $value) */
    public function offsetSet ($offset, $value)
    {
        $this->insert_single ($offset, $value);
    }

    /*  ArrayAccess::offsetUnset (mixed $offset) */
    public function offsetUnset ($offset)
    {
        unset ($this->values[$offset]);
    }
}

// begin test cases
$test_cases = array (
    array (
        'Name' => 'Start Empty, Zero Offset, Single Insert',
        'Initial' => array (),
        'Insert' => 6,
        'Offset' => 0,
        'Output' => array (0 => 6),
    ),
    array (
        'Name' => 'Start Empty, Zero Offset',
        'Initial' => array (),
        'Insert' => array (3, 2),
        'Offset' => 0,
        'Output' => array (0 => 3, 1 => 2),
    ),
    array (
        'Name' => 'Start Empty, Positive Offset, Single Insert',
        'Initial' => array (),
        'Insert' => 'hello',
        'Offset' => 11,
        'Output' => array (11 => 'hello'),
    ),
    array (
        'Name' => 'Start Empty, Positive Offset',
        'Initial' => array (),
        'Insert' => array (9, 'blah'),
        'Offset' => 3,
        'Output' => array (3 => 9, 4 => 'blah'),
    ),
    array (
        'Name' => 'No Shift',
        'Initial' => array (1 => 9),
        'Insert' => array (4, 'blah'),
        'Offset' => 3,
        'Output' => array (1 => 9, 3 => 4, 4 => 'blah'),
    ),
    array (
        'Name' => 'Single Shift',
        'Initial' => array (2 => 13),
        'Insert' => 6,
        'Offset' => 2,
        'Output' => array (2 => 6, 3 => 13),
    ),
    array (
        'Name' => 'Single Element, Double Shift',
        'Initial' => array (2 => 13),
        'Insert' => array (6, 7),
        'Offset' => 2,
        'Output' => array (2 => 6, 3 => 7, 4 => 13),
    ),
    array (
        'Name' => 'Multiple Element, Double Shift',
        'Initial' => array (5 => 13, 6 => 15),
        'Insert' => array (2, 3),
        'Offset' => 5,
        'Output' => array (5 => 2, 6 => 3, 7 => 13, 8 => 15),
    ),
    array (
        'Name' => 'Shift Only Some',
        'Initial' => array (2 => 1, 5 => 13, 6 => 15),
        'Insert' => array (2, 3),
        'Offset' => 5,
        'Output' => array (2 => 1, 5 => 2, 6 => 3, 7 => 13, 8 => 15),
    ),
    array (
        'Name' => 'Shift Fills Gaps',
        'Initial' => array (2 => 0, 3 => 11, 6 => 9, 7 => 'a'),
        'Insert' => array (12, 14),
        'Offset' => 4,
        'Output' => array (2 => 0, 3 => 11, 4 => 12, 5 => 14, 6 => 9, 7 => 'a'),
    ),
);

// run tests
$passes = $failures = 0;
foreach ($test_cases as $case)
{
    $array = new ShiftingArray ($case['Initial']);
    $array->insert ($case['Insert'], $case['Offset']);
    if ($array->get_values () != $case['Output'])
    {
        echo $case['Name'] . " FAILED\n";
        print_r ($array->get_values ());
        print_r ($case['Output']);
        echo "\n\n";
        $failures++;
    }
    else
    {
        $passes++;
    }
}
echo "\n\nTests Finished: $passes Passes, $failures Failures";

【讨论】:

    【解决方案2】:

    一段时间后,我和一个朋友设法让它工作。我相信它对很多人都会有用

    function array_max_key($a){
      if(count($a)) return max(array_keys($a));
      return 0;
    }
    
    function array_insert($a,$b,$index){
      if(!is_array($b)) $b = array($b);
    
      $max = array_max_key($a);
      if($index > $max) $max = $index;
      $ab = array();
      $max++;
    
      for($i=0;$i<$max;$i++){
        if(isset($a[$i]) && $i<$index){
            $ab[$i] = $a[$i];
        }else if($i == $index){
            $_max = count($b);
            for($j=0;$j<$_max;$j++){
                $ab[$i+$j] = $b[$j];
            }
            if(isset($a[$i])) $ab[] = $a[$i];
        }else if(isset($a[$i])){
            if(isset($ab[$i])) $ab[] = $a[$i];
            else $ab[$i] = $a[$i];
        }
      }
    
      return $ab;
    }
    
     array_insert(array(),array(1,2,3),4);
     $a = array(); $a[5] = 1; $a[6] = 2;
     array_insert($a,2,4);
    

    因此,如果您尝试将元素添加到数组的 I 位置,即使该位置不存在(或数组为空),它也会添加它们,并在发现冲突时移动其他元素。元素可以是数组也可以不是数组

    【讨论】:

    • 我认为这并不能真正满足您在改变现有价值观为新价值观让路方面的要求。
    • 当我运行array_insert (array (1,2), array (3,4), 1) 时,我得到array ([0] =&gt; 1, [1] =&gt; 3, [2] =&gt; 4)。 2 被覆盖,没有被推向数组的后面。
    【解决方案3】:

    你说了这么多拼接,我决定不写我的变种。但这不是绝对的:)

    function array_insert($array, $add, $index) {
      // make array with desired keys
      $add = array_combine(range($index, $index + count($add)-1), $add);
      // split old array to two parts - (0 <= key < $index) and ($index <= key) 
      $after = $index ? array_diff_key($array, array_flip(range(0, $index-1))) : $array;
      $before = array_diff($array, $after);
      // Combine arrays
      $array = array_replace($add, $before);
      foreach($after as $item)
         $array[] = $item;
       return($array);    
    }
    
    print_r(array_insert(array(), array(a,b,c), 3));
    // Array ( [3] => a [4] => b [5] => c )
    print_r(array_insert(range(1,10), array(a,b,c), 3));
    // Array ( [3] => a [4] => b [5] => c [0] => 1 [1] => 2 [2] => 3 [6] => 4 [7] => 5 [8] => 6 [9] => 7 [10] => 8 [11] => 9 [12] => 10 )
    print_r(array_insert(range(1,2), array(a,b,c), 3));
    // Array ( [3] => a [4] => b [5] => c [0] => 1 [1] => 2 )
    print_r(array_insert(array(10=>10,3=>3), array(a,b,c), 3));
    // Array ([3] => a [4] => b [5] => c [6] => 10 [7] => 3 )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-09-11
      • 1970-01-01
      • 2018-03-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-16
      相关资源
      最近更新 更多