【问题标题】:Hard PHP nut : how to insert items into one associate array?硬 PHP 坚果:如何将项目插入一个关联数组?
【发布时间】:2011-08-21 08:46:09
【问题描述】:

是的,这是一个有点棘手的问题; 一个 数组(没有副本),而不是任何奇数数组。让我解释一下,让我们从这里开始;

$a = array ( 'one' => 1, 'two' => 2, 'three' => 3, 'four' => 4, 'five' => 5, 'six' => 6 ) ;

假设这个数组很长,超过一百。我一步一步地遍历它,但在某些时候(让我们弥补这发生在第二个项目上)发生了一些事情。也许数据很时髦。尽管如此,我们需要向它添加一些项目以供以后处理,然后继续循环遍历它,而不会丢失当前位置。基本上,我想做这样的事情;

echo current ( $a ) ;  // 'two'
array_insert ( $a, 'four', 'new_item', 100 ) ;
echo current ( $a ) ;  // 'two'

array_insert 的定义是 ($array, $key_where_insert_happens, $new_key, $new_value) ;当然 $new_key 和 $new_value 应该被包装在一个数组包装器中,但这不是重点。这是我想在上面的代码运行后看到的情况;

print_r ( $a ) ; // array ( 'one' => 1, 'two' => 2, 'three' => 3, 'four' => 4, 'new_item' => 100, 'five' => 5, 'six' => 6 ) ;
echo current ( $a ) ;  // 'two'

每当您使用 array_splice、array_slice、array_push 或大多数其他数组摆弄函数时,您基本上都会创建数组的副本,然后您可以将其复制回来,但这会破坏对原始数组的引用和位置好吧,我上面的循环中断了。我可以使用直接引用(即$a['new_item'] = 'whatever;)或将其放在末尾,但这些都不会将项目插入给定位置。

有接受者吗?如何直接将真正的插入到关联数组中(正在其他地方处理)?到目前为止,我唯一的解决方案是;

  1. 记录位置 (current())
  2. 进行拼接/插入 (array_slice)
  3. 用新的 ($old = $new) 覆盖旧数组
  4. 搜索新位置(首先 reset() 然后循环查找 [!!!!!!])

肯定有更好、更简单、更优雅的方式来处理目前笨拙、笨重和笨拙的事情吗?为什么没有一个 array_set_position ( $key ) 函数可以快速解决这个问题,或者一个 array_insert 直接作用于同一个数组(或两者)?

【问题讨论】:

  • 你能保证你添加的项目在当前位置之后吗?如果没有,那么它无论如何都不会得到处理。
  • 听起来你最好使用array_map
  • 埃德,是的,一个恰当的观点。大多数情况下,这是我正在迭代的堆栈,堆栈早期的事件可能会添加稍后运行的事件。
  • samshull,不确定您对此有何看法? Array_map 迭代并在这些项目上运行函数,但不会改变数组中项目的数量,是吗?
  • 好吧,我已经浏览了google.com/codesearch/p?hl=en#EKZaOgYQHwo/unstable/sources/…,除了 Z_ARRVAL_PP 实现的一些改进空间(在源文件中的此注释附近;“/* * 这是魔法发生了。*/" :) 太棒了。

标签: php arrays


【解决方案1】:

也许我没有正确理解你,但你看过array_splice()吗?

这个answer你可能也会感兴趣。


像这样的东西有用吗?

function array_insert($input, $key, $value)
{
    if (($key = array_search($key, array_keys($input))) !== false)
    {
        return array_splice($input, $key, 1, $value);
    }

    return $input;
}


这是我能想到的最好的:

$a = array
(
    'one' => 1,
    'two' => 2,
    'three' => 3,
    'four' => 4,
    'five' => 5,
    'six' => 6,
);

ph()->Dump(next($a)); // 2
array_insert($a, 'four', array('new_item' => 100));
ph()->Dump(current($a)); // 2

function array_insert(&$array, $key, $data)
{
    $k = key($array);

    if (array_key_exists($key, $array) === true)
    {
        $key = array_search($key, array_keys($array)) + 1;
        $array = array_slice($array, null, $key, true) + $data + array_slice($array, $key, null, true);

        while ($k != key($array))
        {
            next($array);
        }
    }
}

ph()->Dump($a);

/*
Array
(
    [one] => 1
    [two] => 2
    [three] => 3
    [four] => 4
    [new_item] => 100
    [five] => 5
    [six] => 6
)
*/

我认为不可能设置数组内部指针without looping

【讨论】:

  • 嗯,它不会保持数组的(内部)位置完整,所以我仍然需要重置和搜索/设置它,不是吗?我对实际拼接没有问题,只是所有提供的拼接都会破坏内部计数器,迫使我处理相当昂贵的手动操作。
  • @AlexanderJohannesen:是的,我想我不完全理解你的问题。你能发布一些虚拟数据和相应的代码/输出吗?
  • @Alix,是的,好的,我已经更新了问题。可能更多的是关于使用键问题更好的 seek_and_set 数组位置... :)
  • @AlexanderJohannesen:知道了。我看不出有什么办法,但让我考虑一下。
  • @AlexanderJohannesen:我刚刚意识到我提出的代码正是你描述的算法......无论如何,这似乎是不可能的,因为array_set_position()pt.php.net/manual/en/function.next.php#52362pt.php.net/manual/en/function.next.php#83087pt.php.net/manual/en/function.current.php#83212 等等……
【解决方案2】:

不要使用关联数组作为事件队列,而是保留一个单独的整数索引数组。循环遍历显式索引变量,而不是使用内部数组位置。

$events = array_keys($a);
for ($i=0; $i < count($events); ++$i) {
    ...
    /* if there's an event to add after $j */
    array_splice($events, $j+1, 0, array($new_event_key));
    $a[$new_event_key] = $new_event_data;
    ...
}

为了让事情更有凝聚力,您可以将两个数组打包成一个事件队列类。

【讨论】:

  • 是的,这是一种方式,尽管我的应用程序依赖于其他事情的密钥。也许它需要拆分,留下更多的序列化工作要做,但也许没有更好的方法?嗯。
  • @Alexander:如果内置数据结构不能满足您的需求,最好的办法是实现您自己的。使用事件队列类,您可以实现IteratorArrayAccess 接口。它将作为一个数组运行,但可以让您更好地控制定位。您甚至可以添加获取和设置位置的方法(可能使用overloading)。
  • 是的,当然,而且我开始这样倾斜。首先,我将了解对数组进行插入/查找操作的成本有多大,如果证明不好,我会这样做。 :) 似乎带有内部指针的哈希图至少有一种按键设置指针的方法,但我可能必须在 'im 上进行所有 OO 操作以使其足够灵活。
猜你喜欢
  • 2023-04-03
  • 1970-01-01
  • 2022-01-13
  • 1970-01-01
  • 1970-01-01
  • 2010-12-16
  • 2019-11-23
  • 2021-01-12
  • 2021-08-30
相关资源
最近更新 更多