Viewed   71 times

I have a multidimensional array that stores people.

Array (
   id93294 => (array (
             Name => "Tom Anderson",
             Birthday => "03/17/1975"),
   id29349 => (array (
             Name => "Tom Anderson",
             Birthday => "03/17/1975")
)

Kind of like that except with more info for the people, so I want to first sort by birthdays THEN sort by another attribute (if their hometown matches their current location) but once I do the second sort on the array it loses the first sort I did using the birthdays...

How do I sort multiple times without it messing up my previous sorts.

P.S. I am using uasort.

 Answers

3

Update

I recently answered this question in a much more capable manner in the "definitive" topic on sorting multidimensional arrays. You can safely skip reading the rest of this answer and directly follow the link for a much more capable solution.

Original answer

The function uasort lets you define your own comparison function. Simply put all the criteria you want inside that.

For example, to sort by birthday and then by name:

function comparer($first, $second) {
    // First see if birthdays differ
    if ($first['birthday'] < $second['birthday']) {
        return -1;
    }
    else if ($first['birthday'] > $second['birthday']) {
        return 1;
    }

    // OK, birthdays are equal. What else?
    if ($first['name'] < $second['name']) {
        return -1;
    }
    else if ($first['name'] > $second['name']) {
        return 1;
    }

    // No more sort criteria. The two elements are equal.
    return 0;
}

I am ignoring the fact that in your example, the birthdays are not in a format that can be ordered by a simple comparison using the operator <. In practice you would convert them to a trivially-comparable format first.

Update: if you think that maintaining a bunch of these multiple-criteria comparers could get ugly real fast, you find me in agreement. But this problem can be solved as any other in computer science: just add another level of abstraction.

I 'll be assuming PHP 5.3 for the next example, in order to use the convenient anon function syntax. But in principle, you could do the same with create_function.

function make_comparer() {
    $criteriaNames = func_get_args();
    $comparer = function($first, $second) use ($criteriaNames) {
        // Do we have anything to compare?
        while(!empty($criteriaNames)) {
            // What will we compare now?
            $criterion = array_shift($criteriaNames);

            // Do the actual comparison
            if ($first[$criterion] < $second[$criterion]) {
                return -1;
            }
            else if ($first[$criterion] > $second[$criterion]) {
                return 1;
            }

        }

        // Nothing more to compare with, so $first == $second
        return 0;
    };

    return $comparer;
}

You could then do:

uasort($myArray, make_comparer('birthday', 'name'));

This example possibly tries to be too clever; in general I don't like to use functions that do not accept their arguments by name. But in this case, the usage scenario is a very strong argument for being too clever.

Wednesday, October 5, 2022
4

You need to iterate over your results, adding a new entry to the output when you encounter a new team, or updating the points value when you find the same team again. This is most easily done by initially indexing the output by the team name, and then using array_values to re-index the array numerically:

$teams = array();
foreach ($results as $result) {
    $team = $result['team'];
    if (!isset($teams[$team])) {
        $teams[$team] = array('team' => $team, 'points' => $result['punti']);
    }
    else {
        $teams[$team]['points'] += $result['punti'];
    }
}
$teams = array_values($teams);
print_r($teams);

Output (for your sample data):

Array
(
    [0] => Array
        (
            [team] => Red Bull Racing
            [points] => 418
        )
    [1] => Array
        (
            [team] => Scuderia Ferrari
            [points] => 353
        )
    [2] => Array
        (
            [team] => Mercedes-AMG
            [points] => 516
        )
    [3] => Array
        (
            [team] => Racing Point F1
            [points] => 147
        )
    [4] => Array
        (
            [team] => Haas F1
            [points] => 127
        )
)

Demo on 3v4l.org

Friday, August 12, 2022
 
2

Since PHP does not support stable sort after PHP 4.1.0, you need to write your own function.

This seems to do what you're asking: http://www.php.net/manual/en/function.usort.php#38827

As the manual says, "If two members compare as equal, their order in the sorted array is undefined." This means that the sort used is not "stable" and may change the order of elements that compare equal.

Sometimes you really do need a stable sort. For example, if you sort a list by one field, then sort it again by another field, but don't want to lose the ordering from the previous field. In that case it is better to use usort with a comparison function that takes both fields into account, but if you can't do that then use the function below. It is a merge sort, which is guaranteed O(n*log(n)) complexity, which means it stays reasonably fast even when you use larger lists (unlike bubblesort and insertion sort, which are O(n^2)).

<?php
function mergesort(&$array, $cmp_function = 'strcmp') {
    // Arrays of size < 2 require no action.
    if (count($array) < 2) return;
    // Split the array in half
    $halfway = count($array) / 2;
    $array1 = array_slice($array, 0, $halfway);
    $array2 = array_slice($array, $halfway);
    // Recurse to sort the two halves
    mergesort($array1, $cmp_function);
    mergesort($array2, $cmp_function);
    // If all of $array1 is <= all of $array2, just append them.
    if (call_user_func($cmp_function, end($array1), $array2[0]) < 1) {
        $array = array_merge($array1, $array2);
        return;
    }
    // Merge the two sorted arrays into a single sorted array
    $array = array();
    $ptr1 = $ptr2 = 0;
    while ($ptr1 < count($array1) && $ptr2 < count($array2)) {
        if (call_user_func($cmp_function, $array1[$ptr1], $array2[$ptr2]) < 1) {
            $array[] = $array1[$ptr1++];
        }
        else {
            $array[] = $array2[$ptr2++];
        }
    }
    // Merge the remainder
    while ($ptr1 < count($array1)) $array[] = $array1[$ptr1++];
    while ($ptr2 < count($array2)) $array[] = $array2[$ptr2++];
    return;
}
?>

Also, you may find this forum thread interesting.

Sunday, October 23, 2022
 
craig_b
 
3

try using str_replace

$content = str_replace(array("<p>&nbsp;</p>n", "&nbsp;<br />n"), array('', ''), $content);

To use regex:

$content = preg_replace('/((<ps*/?>s*)&nbsp;(</ps*/?>s*))+/im', "<p>&nbsp;</p>n", $content);

and for BRs

$content = preg_replace('/(&nbsp;(<brs*/?>s*)|(<brs*/?>s*))+/im', "<br />n", $content);

EDIT Heres why your regex works (hopefully so you can understand it a bit :) ):

/((\ns*))+/im
^  ^^^ ^^  ^^^^
|  |/ ||  |||
|   |  ||  || -- Flags
|   |  ||  |-- Regex End Character
|   |  ||  -- One or more of the preceeding character(s)
|   |  |-- Zero or More of the preceeding character(s)
|   |  -- String Character
|   -- Newline Character (Escaped)
-- Regex Start Character

Every regex expression must start and end with the same character. In this case, i've used the forward slash character.

The ( character indicates an expression block (to replace) The Newline character is n. Because the backslash is used as the escape character in regex, you will need to escape it: \n.

The string character is s. This will search for a string. The * character means to search for 0 or more of the preceeding expression, in this case, search for zero or more strings: s*.

The + symbols searches for ONE or more of the preceeding expresssion. In this case, the preceeding expression is (\ns*), so as long as that expression is found once or more, the preg_replace function will find something.

The flags I've used i and m means case *I*nsensitive, (not really needed for a newline expression), and *M*ultiline - meaning the expression can go over multiple lines of code, instead of the code needing to be on one line.

Friday, September 16, 2022
 
katriel
 
3

You can do it like this, do the calculation from the innermost of the array. Check the demo.

<?php
function f(&$array)
{
    foreach($array as $k => &$v)
    {
        if(is_array($v))
        {
            if(count($v) == count($v, 1))
            {
                unset($array[$k]);
                if($k == 'sum')
                {
                    $v =  array_sum($v);
                    $array[] = $v;

                }elseif($k == 'multiply'){
                    $v = array_product($v);
                    $array[] = $v;
                }else{

                    foreach($v as $vv)
                        $array[] = $vv;
                }
            }else
                f($v);
        }
    }
}

while(count($array) != count($array, 1))
{
    f($array);
}

print_r($array);

Note:

traverse array from outer to inner
traverse array from inner to outer

Monday, November 14, 2022
 
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :