如何正确编写这个usort函数

时间:2010-09-30 20:36:58

标签: php

我有一个数组的行数,我需要按两个参数排序。我试图使用usort()函数来实现这一目标,但我遇到了一些麻烦。

这是我的代码:

if ($sort == 'rating-desc') usort($records, array('browse_model', 'cmp'));
private function cmp($a, $b) {
    $ratingCmp = strcmp($b['rating'], $a['rating']);
    if ($ratingCmp == 0) {
        return strcmp($b['title'], $a['title']);
    } else {
        return $ratingCmp;
    }
}

以下是print_r()之前数组的usort()结果:

Array
(
[0] => Array
    (
        [isbn] => 1847199488
        [title] => CodeIgniter 1.7
        [rating] => 3.5
    )

[1] => Array
    (
        [isbn] => 059615593X
        [title] => CSS Cookbook, 3rd Edition (Animal Guide)
        [rating] => 3.5
    )

[2] => Array
    (
        [isbn] => 0321637984
        [title] => Essential Facebook Development: Build Successful Applications for the Facebook Platform
        [rating] => 3.5
    )

[3] => Array
    (
        [isbn] => 0980576857
        [title] => jQuery: Novice to Ninja
        [rating] => 4.5
    )

[4] => Array
    (
        [isbn] => 0596157134
        [title] => Learning PHP, MySQL, and JavaScript: A Step-By-Step Guide to Creating Dynamic Websites (Animal Guide)
        [rating] => 4.5
    )

)

以下是usort()之后的结果(按评分排序,但不按标题排序):

Array
(
[0] => Array
    (
        [isbn] => 0980576857
        [title] => jQuery: Novice to Ninja
        [rating] => 4.5
    )

[1] => Array
    (
        [isbn] => 0596157134
        [title] => Learning PHP, MySQL, and JavaScript: A Step-By-Step Guide to Creating Dynamic Websites (Animal Guide)
        [rating] => 4.5
    )

[2] => Array
    (
        [isbn] => 0321637984
        [title] => Essential Facebook Development: Build Successful Applications for the Facebook Platform
        [rating] => 3.5
    )

[3] => Array
    (
        [isbn] => 1847199488
        [title] => CodeIgniter 1.7
        [rating] => 3.5
    )

[4] => Array
    (
        [isbn] => 059615593X
        [title] => CSS Cookbook, 3rd Edition (Animal Guide)
        [rating] => 3.5
    )

)

所以它通过评级将它们排序,但不是按标题排列。我如何修改它,以便按评级排序,然后按标题排序?

为了它的价值,我也试过了:

if ($sort == 'rating-desc') {
        foreach ($records as $key => $row) {
            $rating[$key] = $row['rating'];
            $title[$key] = $row['title'];
        }
        array_multisort($title, SORT_DESC, $rating, SORT_ASC, $records);
    }

但结果也不正确。它显示了与我上面尝试过的相同的结果。

我错过了什么?

非常感谢,
马库斯

编辑:按照下面的一些建议,这里有几件我尝试过的事情。他们都没有解决我的问题。他们都返回正确排序的评级,但标题正在下降。

private function cmp($a, $b) {
    if ($a['rating'] == $b['rating']) {
        return strcasecmp($b['title'], $a['title']);
    }
    return $b['rating'] - $a['rating'];
}

private function cmp($a, $b) {
    if ($a['rating'] == $b['rating']) 
        return strcasecmp($a['title'], $b['title']);
    return $b['rating'] - $a['rating'];
}

    if ($sort == 'rating-desc') {
        foreach ($records as $key => $row) {
            $rating[$key] = $row['rating'];
            $title[$key] = $row['title'];
        }
        array_multisort($rating, SORT_DESC, $title, SORT_ASC, $records);
    }

    if ($sort == 'rating-desc') {
        foreach ($records as $key => $row) {
            $rating[$key] = $row['rating'];
            $title[$key] = $row['title'];
        }
        array_multisort($rating, SORT_DESC, $title, SORT_DESC, $records);
    }

这是我的整个代码示例 - 整个模型......

class Browse_model extends Model {

    function Browse_model() {
        parent::Model();
    }

    function get_form_tags() {
        $sql = 'select t.id, t.tag, coalesce(btc.count, 0) as count from tags as t left outer join (select tag_id, count(*) as count from books_tags group by tag_id) as btc on t.id = btc.tag_id order by count desc, tag asc';
        $query = $this->db->query($sql);
        $tags = $query->result();
        return $tags;
    }

    function get_book_info($tags, $andor, $read, $sort) {

        /*
         * SELECT b.isbn, b.title, b.publisher, b.date, b.thumb, b.filename, b.pages, t.tag
         * FROM books AS b
         * INNER JOIN books_tags AS bt ON b.isbn = bt.book_id
         * INNER JOIN tags AS t ON bt.tag_id = t.id
         * ORDER BY b.title, t.tag
         */

        switch ($sort) {
            case 'alpha-desc':
                $order = 'b.title DESC, t.tag';
                break;
            case 'date-desc':
                $order = 'b.date DESC, b.title, t.tag';
                break;
            case 'date-asc':
                $order = 'b.date, b.title, t.tag';
                break;
            default:
                $order = 'b.title, t.tag';
                break;
        }

        $this->db->select('b.isbn, b.title, b.publisher, b.date, b.thumb, b.filename, b.pages, t.tag');
        $this->db->from('books AS b');
        $this->db->join('books_tags AS bt', 'b.isbn = bt.book_id', 'inner');
        $this->db->join('tags AS t', 'bt.tag_id = t.id', 'inner');
        $this->db->order_by($order);
        $query = $this->db->get();
        $result = $query->result();

        $counter = '';
        $records = $meta = $tags = array();
        $count = count($result);
        $i = 1;

        foreach ($result as $book) {
            // If this is not the last row
            if ($i < $count) {
                // If this is the first appearance of this book
                if ($counter != $book->isbn) {
                    // If the meta array already exists
                    if ($meta) {
                        // Add the combined tag string to the meta array
                        $meta['tags'] = implode(', ', $tags);
                        // Add the meta array
                        $records[] = $meta;
                        // Empty the tags array
                        $tags = array();
                    }
                    // Reset the counter
                    $counter = $book->isbn;
                    // Grab the book from Amazon
                    $amazon = $this->amazon->get_amazon_item($book->isbn);
                    // Collect the book information
                    $meta = array(
                        'isbn' => $book->isbn,
                        'title' => strip_slashes($book->title),
                        'publisher' => strip_slashes($book->publisher),
                        'date' => date('F j, Y', strtotime($book->date)),
                        'thumb' => $book->thumb,
                        'file' => $book->filename,
                        'pages' => $book->pages,
                        'rating' => $amazon->Items->Item->CustomerReviews->AverageRating,
                        'raters' => $amazon->Items->Item->CustomerReviews->TotalReviews
                    );
                    // Add the tag to the tags array
                    $tags[] = $book->tag;
                } else {
                    // All we need is the tag
                    $tags[] = $book->tag;
                }
            // If this is the last row
            } else {
                // If this is the first appearance of this book
                if ($counter != $book->isbn) {
                    // Grab the book from Amazon
                    $amazon = $this->amazon->get_amazon_item($book->isbn);
                    // Collect the book information
                    $meta = array(
                        'isbn' => $book->isbn,
                        'title' => strip_slashes($book->title),
                        'publisher' => strip_slashes($book->publisher),
                        'date' => date('F j, Y', strtotime($book->date)),
                        'thumb' => $book->thumb,
                        'file' => $book->filename,
                        'pages' => $book->pages,
                        'rating' => $amazon->Items->Item->CustomerReviews->AverageRating,
                        'raters' => $amazon->Items->Item->CustomerReviews->TotalReviews
                    );
                }
                // All we need is the tag
                $tags[] = $book->tag;
                // Add the combined tag string to the meta array
                $meta['tags'] = implode(', ', $tags);
                // Add the meta array
                $records[] = $meta;
            }
            $i++;
        }

        echo '<code><pre>';
        print_r($records);
        echo '</pre></code>';

        if ($sort == 'rating-desc') usort($records, array('browse_model', 'cmp'));

        echo '<code><pre>';
        print_r($records);
        echo '</pre></code>';
        return $records;
    }

    private function cmp($a, $b) {
        if ($a['rating'] == $b['rating']) 
            return strcasecmp($b['title'], $a['title']);
        return $b['rating'] - $a['rating'];
    }


}

3 个答案:

答案 0 :(得分:5)

您的数组按评分和标题排序。问题是你要区分大小写,'a'来自'Z'。

比较标题时,请尝试使用strcasecmp代替strcmp

此外,如果评级始终是一个数字,您可能应该用数字而不是字符串比较评级。使用$b['rating'] - $a['rating']代替strcmp

编辑:

我使用了你原来的相同功能和相同的数据,并制作了一个测试脚本。使用类中的函数并标记为private,PHP警告说usort的回调无效,但继续运行(不接触数组)。但是,使用标记为public的函数,它可以按预期工作。这让我相信PHP不喜欢你的回调属于私有函数,或者类名错误。

如果您希望能够使用私有函数,则usort的调用显然需要在同一个类中的函数中。否则usort会抱怨回调无效并拒绝运行。

class Stuff
{
    public function sort(&$arr)
    {
        usort($arr, array('Stuff', 'cmp'));
    }

    private function cmp($a, $b)
    {
        $ratingCmp = $b['rating'] - $a['rating'];
        if ($ratingCmp == 0) {
            return strcasecmp($a['title'], $b['title']);
        } else {
            return $ratingCmp;
        }
    }
}

Stuff::sort($records);
print_r($records);

对我来说,这会打印出按评级递减的书籍,然后按标题递增。如果这对你不起作用,那就有点时髦了。

答案 1 :(得分:2)

使用简单的布尔比较运算符来比较数字字段,例如评级,而不是strcmp

private function cmp($a, $b) {
    if ($b['rating'] == $a['rating'])
       return strcmp($b['title'], $a['title']);
    return $b['rating'] - $a['rating'];
}

看起来你的评分和头衔都在下降;将您的strcmp更改为return strcmp($a['title'], $b['title']),以按评分(降序)和标题(升序)排序。

答案 2 :(得分:1)

您也可以使用array_multisort()

已删除的代码

创建一些额外的数组,但完成工作;如果您将代码放入函数或方法中(通过引用传递$ record),那么这些代码将在函数退出时被销毁。

编辑:我看到你已经提出了你已经尝试过的问题。它怎么不起作用?

编辑:这对我有用:

foreach ($records as $rec) {
    $rating[] = $rec['rating'];
    $title[] = strtolower($rec['title']);
}

array_multisort($title, SORT_DESC, $rating, SORT_ASC, $records);

print_r($records);

另一个编辑:

鉴于此数组:

$records = array(
  0 => 
  array (
    'isbn' => '1847199488',
    'title' => 'CodeIgniter 1.7',
    'rating' => 3.5,
  ),
  1 => 
  array (
    'isbn' => '1847199488',
    'title' => 'CodeIgniter 1.7',
    'rating' => 3,
  ),
  2 => 
  array (
    'isbn' => '1847199488',
    'title' => 'CodeIgniter 1.7',
    'rating' => 3.2,
  ),
  3 => 
  array (
    'isbn' => '1847199488',
    'title' => 'CodeIgniter 1.7',
    'rating' => 4.5,
  ),
  4 => 
  array (
    'isbn' => '059615593X',
    'title' => 'CSS Cookbook, 3rd Edition (Animal Guide)',
    'rating' => 3.5,
  ),
  5 => 
  array (
    'isbn' => '0321637984',
    'title' => 'Essential Facebook Development: Build Successful Applications for the Facebook Platform',
    'rating' => 3.5,
  ),
  6 => 
  array (
    'isbn' => '0980576857',
    'title' => 'jQuery: Novice to Ninja',
    'rating' => 4.5,
  ),
  7 => 
  array (
    'isbn' => '0596157134',
    'title' => 'Learning PHP, MySQL, and JavaScript: A Step-By-Step Guide to Creating Dynamic Websites (Animal Guide)',
    'rating' => 4.5,
  ),
);

此代码:

foreach ($records as $rec) {
    $rating[] = $rec['rating'];
    $title[] = strtolower($rec['title']);
}

array_multisort($rating, SORT_DESC, SORT_NUMERIC, $title, SORT_ASC, SORT_STRING, $records);

var_export($records);

会产生这个:

array (
  0 => 
  array (
    'isbn' => '1847199488',
    'title' => 'CodeIgniter 1.7',
    'rating' => 4.5,
  ),
  1 => 
  array (
    'isbn' => '0980576857',
    'title' => 'jQuery: Novice to Ninja',
    'rating' => 4.5,
  ),
  2 => 
  array (
    'isbn' => '0596157134',
    'title' => 'Learning PHP, MySQL, and JavaScript: A Step-By-Step Guide to Creating Dynamic Websites (Animal Guide)',
    'rating' => 4.5,
  ),
  3 => 
  array (
    'isbn' => '1847199488',
    'title' => 'CodeIgniter 1.7',
    'rating' => 3.5,
  ),
  4 => 
  array (
    'isbn' => '059615593X',
    'title' => 'CSS Cookbook, 3rd Edition (Animal Guide)',
    'rating' => 3.5,
  ),
  5 => 
  array (
    'isbn' => '0321637984',
    'title' => 'Essential Facebook Development: Build Successful Applications for the Facebook Platform',
    'rating' => 3.5,
  ),
  6 => 
  array (
    'isbn' => '1847199488',
    'title' => 'CodeIgniter 1.7',
    'rating' => 3.2,
  ),
  7 => 
  array (
    'isbn' => '1847199488',
    'title' => 'CodeIgniter 1.7',
    'rating' => 3,
  ),
)
相关问题