比较多维数组中的值

时间:2012-08-22 10:28:22

标签: php arrays multidimensional-array

我有两个数组阵列,其键有'menu_title'和'id'。

我想通过这两个数组并在第三个数组中存储第一个数组中任何数组的id,该数组与第二个数组中的数组共享'menu_title'。

我知道我可以这样做:

$collision = [];
foreach($children as $child)
    foreach($siblings as $sibling)
        if($child['menu_title'] == $sibling['menu_title'])
            $collision[] = $child['id'];

但这意味着我在第一个数据中循环第二个数组。

也许这会更好?

$collision = [];
foreach($siblings as &$sibling)
        $sibling = $sibling['menu_title'];

    foreach($children as $child)
        if(in_array($child['menu_title'], $siblings))
            $collision[] = $child['id'];

但我仍然认为必须有更好的方法吗?


更新

数组由sql填充,基本上如果我删除了一个类别,那么我将子类别移动到与我要删除的类别相同的级别。

但是如果任何一个孩子与一个删除类别的兄弟姐妹有相同的menu_title,那么我需要将孩子的menu_title重命名为“whatever-1”,例如“计算机-1”

所以我正在构建一个我需要更新的id数组,然后我将对这些ID进行sql更新,可能会对我如何接近这个进行增强?


更新

所以,最后我最终得到了:

$id = 4;
$category = $this->categoryeditormodel->getCategory($id);
$children = $this->categoryeditormodel->getChildCategories($id);
$siblings = $this->categoryeditormodel->getSiblingCategories($id);

foreach($siblings as &$sibling)
    $sibling = $sibling['menu_title'];

foreach($children as &$child){
    $child['parent_id'] = $category['parent_id'];
    if(in_array($child['menu_title'], $siblings)){
        $i = 0;
        while(in_array(($name = ($child['menu_title'].'-'.++$i)), $siblings));
        $child['menu_title'] = $name;
    }
}
$this->categoryeditormodel->update_batch($children);

顶部的三个函数按照他们的说法执行,但它们很便宜,因为类别已经加载到缓存中,因此它不是另一个SQL查询。

和update_batch只是Code Igniters update_batch函数的快捷方式,但它通过表名和id键。

有什么想法吗?

4 个答案:

答案 0 :(得分:2)

本质上这是O(m * n),其中m和n是两个数组的大小 - 所以你不能做得那么好。最后,您需要查看每个(兄弟,子)对,除非您可以更具体地说明这些数组是如何填充的,否则没有太大的改进空间。

可能会有一些调整来优化这一点,但没有一个立即发生在我身上,并且可能没有任何东西可以产生显着的差异。

编辑:如果你对两个数组排序,首先是O(n * log n + m * log m),那么你可能会根据数组中的实际值进行渐近改进。除非数组相当大,否则这可能没用。

答案 1 :(得分:1)

您可以直接在SQL中执行此操作。

我假设类别表类似于(我缩进了标题以显示原始层次结构):

id    parent title
1     0      computers
2     1         laptop
3     1         desktop
4     1         *servers*     <--
5     0      *servers*        <--
6     0      printers

并且您要删除ID为1的“计算机”,我将其称为DEL_ID。你这样做:

  • 检索有关行DEL_ID的信息,尤其是父类别ID PAR_ID
  • 更新父级为DEL_ID的所有行,使其父级成为PAR_ID
  • 删除ID为DEL_ID的行。

执行此操作时,您需要检查父级为DEL_ID的行是否与父级PAR_ID的任何行具有相同的标题。当他们这样做时,你更新他们的名字。

所以在SQL中:

UPDATE table SET title = CONCAT(title, '-1') FROM table
    JOIN table AS check ON (
        table.parent = DEL_ID
        AND check.parent = PAR_ID
        AND table.title = check.title);

UPDATE table SET parent = PAR_ID WHERE parent = DEL_ID;
DELETE FROM table WHERE id = DEL_ID;

出于某种原因,您可能会出现在victimCategory的兄弟姐妹中已经拥有'title'和'title-1'的问题,而其中一个孩子又是'title'。在这种情况下,将'title'重命名为'title-1'将导致冲突(与PHP实现中的问题相同)。

您可以通过将第一个UPDATE转换为SELECT并检索类别的“旧”和“建议”标题来检测这种情况,然后运行新的SELECT以验证没有重复项是否接受“建议” “ 名称;并重复递增-1,-2等后缀,直到检查选择不返回冲突的行。或者你可以一举检索所有标题LIKE你的旧“标题%”,如果有任何标题(意味着你会有冲突),请选择数字,而不是按字典顺序,更大 - 即标题-11是> title-2 - ,将其数字增加1并将其用于新更新,现在必须逐个更新。它/是/昂贵的,但我想这很少会发生。

答案 2 :(得分:0)

我认为没有更好的方法可以做到这一点。如果要比较两个数组,则必须在循环中遍历它们。您可以在数据库中创建索引,但如果您的数组不包含&gt; 1000?不值得的元素。

无论如何,要创建一个索引:

$index = array();
foreach($siblings as $sibling)
{
  $index[$sibling['menu_title']] = true;
}
foreach($children as $child)
{
  if (isset($index[$child['menu_title']])) $collision[] = $child['id'];
}

答案 3 :(得分:0)

$collision = array_intersect($children, $siblings);

这应该让您获得具有重复值的数组。查看array_intersect