views:

142

answers:

2

I cant come up with any sane solution for this problem without resorting to ridiculous combinations of custom functions. Maybe you can provide some fresh thought on this.

I have the follow (simplified) array

Array
(
    [0] => Array
        (
            [vid_id] => 420037
            [vid_rating] => 2.93827
            [vid_quality] => 2
            [vid_special] => 1
            [vid_weight] => 0
            [vid_position] => 0
            [vid_position_end] => 0
        )

    [1] => Array
        (
            [vid_id] => 420040
            [vid_rating] => 3
            [vid_quality] => 1
            [vid_special] => 1
            [vid_weight] => 0
            [vid_position] => 0
            [vid_position_end] => 0
        )

    [2] => Array
        (
            [vid_id] => 426455
            [vid_rating] => 3.25581
            [vid_quality] => 2
            [vid_special] => 0
            [vid_weight] => 5
            [vid_position] => 1
            [vid_position_end] => 2
        )

    [3] => Array
        (
            [vid_id] => 429804
            [vid_rating] => 3
            [vid_quality] => 2
            [vid_special] => 0
            [vid_weight] => 0
            [vid_position] => 0
            [vid_position_end] => 0
        )

    [4] => Array
        (
            [vid_id] => 420848
            [vid_rating] => 2.94444
            [vid_quality] => 2
            [vid_special] => 0
            [vid_weight] => 3
            [vid_position] => 1
            [vid_position_end] => 2
        )

    [5] => Array
        (
            [vid_id] => 420859
            [vid_rating] => 2.73077
            [vid_quality] => 2
            [vid_special] => 0
            [vid_weight] => 4
            [vid_position] => 1
            [vid_position_end] => 2
        )

    [6] => Array
        (
            [vid_id] => 420524
            [vid_rating] => 2.41379
            [vid_quality] => 2
            [vid_special] => 0
            [vid_weight] => 5
            [vid_position] => 2
            [vid_position_end] => 2
        )

    [7] => Array
        (
            [vid_id] => 419810
            [vid_rating] => 3.13393
            [vid_quality] => 1
            [vid_special] => 0
            [vid_weight] => 0
            [vid_position] => 0
            [vid_position_end] => 0
        )

    [8] => Array
        (
            [vid_id] => 419851
            [vid_rating] => 2.97802
            [vid_quality] => 1
            [vid_special] => 0
            [vid_weight] => 5
            [vid_position] => 1
            [vid_position_end] => 2
        )

    [9] => Array
        (
            [vid_id] => 419843
            [vid_rating] => 2.95349
            [vid_quality] => 1
            [vid_special] => 0
            [vid_weight] => 3
            [vid_position] => 1
            [vid_position_end] => 2
        )

    [10] => Array
        (
            [vid_id] => 419838
            [vid_rating] => 2.73529
            [vid_quality] => 1
            [vid_special] => 0
            [vid_weight] => 4
            [vid_position] => 1
            [vid_position_end] => 2
        )

)

This array is a result of this mysql query

    SELECT 
    vid_id,
    vid_rating,
    vid_quality,
    vid_special,
    vid_weight,
    vid_position,
    vid_position_end
FROM versions
WHERE vid_movid = 'xxxxx' AND vid_status = 1 
ORDER BY vid_special DESC, vid_quality DESC, vid_rating DESC

This outputs a list of website links (actual link column is removed for simplicity), that need to be put in a very specific order. Doing what I need done is possible with several UNIONed queries.... but i really dont want to resort to that, since the cost will be very high, so I figured manipulating the arrays would be easier.

I need to selectively extract several links from this array, and stick them on top of the array, in a certain order.

  • Links marked with vid_position, and vid_position_end denote a range that this group will occupy. Meaning that if there are several links marked with those positions, only 2 will be pushed to the top, if the range is 1-2. if its 1-3, then top 3 positions will be occupied.

  • The weight denotes the ORDER in which links must be sorted. So if there are 5 different links, with 5 different weights in a position range of 1-2, only the top 2 weights will be pushed to the top. The remaining 3 will remain where they are.

  • there are different groups of links. In this case, there is a group 1-2, and 3-3. First group occupies the first 2 positions, and in my example has 3 weight classes. the other group occupires the 3rd position, and only has 1 weight class.

  • The ordering should be independent. If there are no links in the 1-2 group, but there are links in 3-3, that means 3-3 grouped links will appear in the first position.

+1  A: 

For each element in the array, create an entry in a 'sort_by' array where the entry is set to a sort "score" that you create.

The score is generated by your algorithm for ordering your entries. Remember that you can create a score with large numbers. Eg, the most minor sort order is multiplied by 10, the next most minor sort order is multiplied by 100, next by 1000, then add up the numbers to get the score for the entry.

Then use http://stackoverflow.com/questions/348410/php-sort-an-array-based-on-another-array to sort the main array by the sort_by array

Added: This method is good if it is slow or expensive to figure out ordering between two original array elements since the scoring is only done once per original array element. If the ordering is easy, then using uasort will probably be clearer code.

Larry K
Not sure I understand your score generating algorithm. Do you have any kind of example?
Yegor
@Yegor, the issue is to turn your description of how to order your original array into numeric values which can then be compared. The problem is that I don't understand your description. An example: if items have a weight, a rating and a quality and the least important sort order is the weight * quality and the more important is the rating, and all the numbers are 0-9, then score = (weight * quality) + (rating * 100). That way, a rating of 1 with lowest quality and weight scores will be before a rating of 0 with highest qual and weight scores. The multipliers depend on the possible values
Larry K
quality doesn't need to be touched. the only factors that come into play is vid_weight + vid_position (start) and vid_position_end. the special values need to be plucked from the array, and simply put on top. the order of the remaining items is fine the way it is.
Yegor
A: 

For hand tailored array sorting I would use uasort or one of it's relative functions.

Itay Moav