简体   繁体   中英

Sort array by value, then randomly within those values BUT group certain elements - or revise MySQL query to combine it all?

So, let's say I want to sort an array in this order: 1) sort by total_weight 2) sort within those weights randomly 3) if there's an item within the same weight that is similar in name, group those items

This would result in something like so:

name: Delta 1 - total_weight: 5
name: Delta 1b - total_weight: 5
name: Charlie 12 - total_weight: 5
name: Charlie 12b - total_weight: 5
name: Charlie 12c - total_weight: 5
name: Alpha 10 - total_weight: 4
name: Delta 2 - total_weight: 3
name: Delta 2b - total_weight: 3
name: Bravo 5 - total_weight: 3

The array prior to sorting looks like so:

Array
(
[463] => stdClass Object
(
    [name] => Delta 1b
    [total_weight] => 5
)
[463] => stdClass Object
(
    [name] => Charlie 12
    [total_weight] => 5
)
[340] => stdClass Object
(
    [name] => Charlie 12b
    [total_weight] => 5
)
[340] => stdClass Object
(
    [name] => Charlie 12c
    [total_weight] => 5
)
[342] => stdClass Object
(
    [name] => Delta 1
    [total_weight] => 5
)
[532] => stdClass Object
(
    [name] => Alpha 10
    [total_weight] => 4
)
[203] => stdClass Object
(
    [name] => Bravo 5
    [total_weight] => 3
)
[206] => stdClass Object
(
    [name] => Delta 2
    [total_weight] => 3
)
[208] => stdClass Object
(
    [name] => Delta 2b
    [total_weight] => 3
)

I know that to sort by weight, then by alphabetical I could use usort:

function _sort_by_total_weight($a, $b)
{
    if ($a->total_weight == $b->total_weight) {
        return strcmp($a->name, $b->name);
    }
    return ($a->total_weight > $b->total_weight) ? -1 : 1;
}

But, I want the results to not be alphabetical and feel random, yet group together some relevant tracks. I realize I could throw a row in the db for sort order or something, but with 10,000+ records, it's not easily implemented. Any thoughts on how to crack this nut?

EDIT : So, I reworked this on the db side (MySQL) so that the query is weighted and ordered before it hits php:

$this->db->select('tracks.id, 
                            tracks.name AS name, 
                            tracks.filename, 
                            tracks.url_name, 
                            tracks.file_path_high, 
                            tracks.filesize, 
                            tracks.categories,
                            tracks.duration, 
                            tracks.folder,
                            links.tag_id,
                            SUM(links.weight) AS total_weight,
                            tag_data.tag_name');

        $this->db->distinct();
        $this->db->from('music AS tracks');
        $this->db->where_in('links.tag_id', array('1', '2');
        $this->db->join('linked_tags AS links', 'links.track_id = tracks.id', 'inner');
        $this->db->join('tags AS tag_data', 'tag_data.id = links.tag_id', 'inner');
        $this->db->group_by("name", "total_weight");
        $this->db->order_by('total_weight DESC, RAND(123)'); 
        $this->db->limit($total, $offset);

But, now I have some near-duplicate entries in the result. For the where_in, is there a way to state that I only want entries that have entries for both 1, and 2 and not have it return all entries where 1 matches OR 2 matches?

You could shuffle() your array results. Example from PHP.net:

<?php
   $numbers = range(1, 20);
   shuffle($numbers);
   foreach ($numbers as $number) {
      echo "$number ";
   }
?>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM