【问题标题】:How to reorder this array?如何重新排序这个数组?
【发布时间】:2011-11-25 19:24:30
【问题描述】:

我有一个数据库表如下:

这会返回图片中的所有列标题,但最重要的是 slugparent(不确定 id_button)。

数组由 id_button ASC 自动排序,这让我很恼火。但是,无论如何,这并不重要,因为我需要对它进行完全不同的排序,或者在填充数组后重新排序。

数组按 id_button 的顺序返回:

$new_menu_buttons = array(
    0 => array(
            'id_button' => 1,
            'parent' => 'help',
            'position' => 'child_of',
            'slug' => 'testing',
    ),
    1 => array(
            'id_button' => 2,
            'parent' => 'packages',
            'position' => 'after',
            'slug' => 'sub_test_1',
    ),
    2 => array(
            'id_button' => 3,
            'parent' => 'google.com',
            'position' => 'after',
            'slug' => 'another_test',
    ),
    3 => array(
            'id_button' => 4,
            'parent' => 'testing'
            'position' => 'child_of',
            'slug' => 'google.com',
    )
);

我需要订购它,以便如果在任何parent 中找到slug,则需要先加载parent 中的slug,然后再加载在父级中定义的slug

如果它直接在它之前并不重要。例如,您看到testing 是第一个返回的slug,但它的父级是最后一个 slug (google.com)。因此,只要对定义父项的 slug 行进行排序,使其位于父列中具有 slug 值的行之前,一切都很好。

所以在这种情况下,它可以重新排序为以下这 3 个有序数组中的任何一个:

$new_menu_buttons = array(
    0 => array(
            'id_button' => 1,
            'parent' => 'help',
            'position' => 'child_of',
            'slug' => 'testing',
    ),
    1 => array(
            'id_button' => 2,
            'parent' => 'packages',
            'position' => 'after',
            'slug' => 'sub_test_1',
    ),
    2 => array(
            'id_button' => 4,
            'parent' => 'testing',
            'position' => 'child_of',
            'slug' => 'google.com',
    ),
    3 => array(
            'id_button' => 3,
            'parent' => 'google.com'
            'position' => 'after',
            'slug' => 'another_test',
    )
);

或者这个...

$new_menu_buttons = array(
    0 => array(
            'id_button' => 1,
            'parent' => 'help',
            'position' => 'child_of',
            'slug' => 'testing',
    ),
    1 => array(
            'id_button' => 4,
            'parent' => 'testing',
            'position' => 'child_of',
            'slug' => 'google.com',
    ),
    2 => array(
            'id_button' => 2,
            'parent' => 'packages',
            'position' => 'after',
            'slug' => 'sub_test_1',
    ),
    3 => array(
            'id_button' => 3,
            'parent' => 'google.com'
            'position' => 'after',
            'slug' => 'another_test',
    )
);

或者甚至这个...

$new_menu_buttons = array(
    0 => array(
            'id_button' => 1,
            'parent' => 'help',
            'position' => 'child_of',
            'slug' => 'testing',
    ),
    1 => array(
            'id_button' => 4,
            'parent' => 'testing',
            'position' => 'child_of',
            'slug' => 'google.com',
    ),
    2 => array(
            'id_button' => 3,
            'parent' => 'google.com'
            'position' => 'after',
            'slug' => 'another_test',
    ),
    3 => array(
            'id_button' => 2,
            'parent' => 'packages',
            'position' => 'after',
            'slug' => 'sub_test_1',
    )
);

所有这 3 个有序数组都可以工作,因为与 parent 匹配的 slug 数组在匹配 parent 的数组之前,并且由于 slug 值,sub_test_1 不匹配任何在parent 值中,此数组顺序并不重要,因此该数组可以位于数组中的任何位置。

我该怎么做?我正在考虑以某种方式遍历数组并尝试确定蛞蝓是否在任何父母中,然后以某种方式重新排序......

简而言之,slug 需要在 parent 之前排序,前提是数组中存在与 slug 匹配的 parent。否则,如果找不到匹配项,则顺序不重要。

【问题讨论】:

  • 通常解决这个问题的最好方法是尽可能将排序留给数据库。
  • 如何通过数据库来完成?但是,因为数据库查询目前没有对任何内容进行排序,所以它仍然使用 id_button 以升序返回数组。
  • 如何从那里获取数据?
  • 另外,有人告诉我,如果您要抓取表格的全部内容,那么您应该使用ORDER BY NULL,这样就不会有任何内存问题。所以我在桌子上使用这个顺序。
  • 好吧,它不必返回与新订单相同的数组。它也可以返回具有新顺序的不同数组。因为我需要将有序数组传递给一个函数,所以如果有序数组是不同的名称,这不是问题。

标签: php sorting multidimensional-array


【解决方案1】:

正如 Niko 所建议的,数据库支持强大的排序功能,因此您通常可以通过告诉数据库以什么顺序返回数据来最好地解决这个问题。如果用SQL查询数据,那就是ORDER BY子句。这在您的数据库文档中指定,假设您使用的是 MySQL 5.0:http://dev.mysql.com/doc/refman/5.0/en/sorting-rows.html

如果您不能影响数据库级别的顺序,则需要在 PHP 中对数组进行排序。您实际上有一个数组数组,其中外部数组只是一个列表,其中每行的id(主键)和其他字段作为字段名-> 值数组作为值(内部数组)。

您的排序是 *user-defined` - 您指定排序顺序。一种常见的方法是使用一个排序函数来比较两个彼此的条目。该排序功能需要确定这两者中的哪一个具有比另一个更高的排序顺序(或两者具有相同的权重)。在您的情况下,如果一项是另一项的子项,则一项高于另一项。

这是一般原则。您定义决定的排序函数(所谓的 callback 函数),PHP 会小心地将数组数据提供给它以使用 usortDocs 函数进行排序。

然后您需要解决的一个子问题是确定整个数组中是否存在子项(具有与父项具有相同值的 slug 的项)。由于这一切看起来可能有点复杂,因此将这一切封装到它自己的类中是明智的。

例子/Demo:

class menuButtons
{
    /**
     * @var array
     */
    private $buttons;

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


    public function sortChildsFirst()
    {
        $buttons = $this->buttons;
        usort($buttons, array($this, 'sortCallback'));
        return $buttons;
    }

    private function sortCallback($a, $b)
    {
        // an element is more than any other if it's parent
        // value is any other slugs value

        if ($this->slugExists($a['parent']))
            return 1;

        return -1;
    }

    private function slugExists($slug)
    {
        foreach($this->buttons as $button)
        {
            if ($button['slug'] === $slug)
                return true;
        }
        return false;
    }
}

$buttons = new menuButtons($new_menu_buttons);

$order = $buttons->sortChildsFirst();

注意:此代码利用了您的排序顺序只是粗略指定的事实。你只写了先生孩子,再生父母,所以如果你先把所有的孩子都带走,总是这样。并不是每个父母都会直接跟随孩子。

尽管如此,这个骨架类可以作为一个基础来进一步改进搜索功能,因为它是完全封装的。您甚至可以更改整个排序方法,例如即使没有usort,也可以完全编写自己的一个,例如outlined below。主要代码不需要更改,因为它只使用了sortChildsFirst 方法。

【讨论】:

  • 对不起,查看您的演示示例,这将返回与数组完全相同的顺序。这对我有什么帮助???
  • @SoLoGHoST:您写道,孩子必须早于parten,获得排序顺序。如果这不是您想要的,您需要更改搜索功能,例如与stereofrog 概述的内容。此外,您可以在您的问题中更准确地描述排序顺序实际上是什么,您使用的措辞非常含糊,从示例数据来看,标准是什么也不是很清楚。
  • 如果发现parent 列中的值与slugs 列中的任何值匹配,则其中包含 slug 的行需要位于其父行之前那个蛞蝓。您的示例返回完全相同的数组,这根本没有任何意义,因为没有任何东西与原始数组有任何不同。
  • 顺便说一句,将此添加到我的问题中,但也会对其发表评论......如果它直接在它之前并不重要。例如,您会看到 testing 是第一个返回的 slug,但它的父级是最后一个 slug (google.com)。因此,只要对定义父项的 slug 行进行排序,使其位于父列中具有 slug 值的行之前,一切都很好。
  • 简而言之,slug 需要在 parent 之前排序,前提是数组中存在与 slug 匹配的 parent。否则,如果找不到匹配项,则顺序不重要。
【解决方案2】:

您可以使用 usort() 函数对填充后的数组进行排序。

http://php.net/manual/en/function.usort.php

【讨论】:

  • 不排序删除数组的所有键值吗?我在想 usort 重置数组索引,并且不确定这是否是我想要做的。可能最适合第一个索引,但不是所有索引...你能给我一个使用这个函数的例子吗?顺便说一句?谢谢:)
  • 您是否介意提供一个示例,如何使用usort 回调和指定的数据/排序顺序来做到这一点?我认为这不是您在答案中概述的那么微不足道(甚至可能吗?)。
  • 有一个类似的函数可以保存索引:uasortphp.net/manual/en/function.uasort.php
  • 嘿,谢谢,但我认为我根本不需要这个。请看下面我的回答。干杯:)
【解决方案3】:

由于您的结构类似于树,因此首先想到的是用它构建一棵树。它是这样的:

$tree = array();

foreach($array as $e) {
    $p = $e['parent'];
    $s = $e['slug'];
    if(!isset($tree[$p]))
        $tree[$p] = new stdclass;
    if(!isset($tree[$s]))
        $tree[$s] = new stdclass;
    $tree[$s]->data = $e;
    $tree[$p]->sub[] = $tree[$s];
}

这将创建一组对象,其中成员 datasub = 子对象列表。 现在我们迭代树并为每个“根”节点,将它及其子节点添加到排序数组中:

$out = array();

foreach($tree as $node)
    if(!isset($tree[$node->data['parent']]))
        add($out, $node);

add() 在哪里

function add(&$out, $node) {
    if(isset($node->data))
        $out[] = $node->data;
    if(isset($node->sub))
        foreach($node->sub as $n)
            add($out, $n);
}

希望这会有所帮助。

【讨论】:

    【解决方案4】:

    好的,首先让我感谢大家的详细解释。它们非常直观。但是,我找到了另一种方法,如果您在这里发现这种方法有什么问题,请告诉我吗?

    Click here to see a Demo of this working!

    $temp_buttons = array();
    foreach($new_menu_buttons as $buttons)
        $temp_buttons[$buttons['parent']] = $buttons['slug'];
    
    
    dp_sortArray($new_menu_buttons, $temp_buttons, 'slug');
    
    // The $new_menu_buttons array is now sorted correctly!  Let's check it...
    var_dump($new_menu_buttons);
    
    function dp_sortArray(&$new_menu_buttons, $sortArray, $sort)
    {
        $new_array = array();
        $temp = array();
        foreach ($new_menu_buttons as $key => $menuitem)
        {
            if (isset($sortArray[$menuitem[$sort]]))
            {
                $new_array[] = $menuitem;
    
                $temp[$menuitem['parent']] = $menuitem['slug'];
                unset($new_menu_buttons[$key]);
            }   
        }
    
        $ordered = array();
    
        if (!empty($new_array))
        {
            foreach ($new_array as $key => $menuitem)
            {
                if (isset($temp[$menuitem[$sort]]))
                {
                    $ordered[] = $menuitem;
                    unset($new_array[$key]);
                }
            }
        }
        else
        {
            $new_menu_buttons = $new_menu_buttons;
            return;
        }
    
        $new_menu_buttons = array_merge($ordered, $new_array, $new_menu_buttons);
    }
    

    似乎在我测试的所有情况下都有效,但当然,它们可能是某个地方的缺陷。大家对此怎么看?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-29
      • 1970-01-01
      • 2012-02-14
      • 1970-01-01
      • 2011-01-27
      相关资源
      最近更新 更多