0

I have a multi-dimensional array and I want to sort it. The array looks like this:

$test_arr = [
    /* artist               albums  tracks */
    [ "Green Day",          "8",    "26",   ],
    [ "Remy Zero",          "1",    "2",    ],
    [ "System of a Down",   "1",    "1",    ],
    [ "Modern Talking",     "1",    "1",    ],
    [ "Snow Patrol",        "1",    "2",    ],
    [ "Linkin Park",        "6",    "18",   ],
];

I want to sort the artists with respect to their albums and tracks numbers. To do that, I have created a function.

function sort_mul_dim_arr($mul_dim_arr, $sort_col) {
    $control_arr = [];
    for ($i = 0; $i < count($mul_dim_arr); $i++) {
        array_push($control_arr, $mul_dim_arr[$i][$sort_col]);
    }
    sort($control_arr);
    $sorted_arr = [];
    for ($i = 0; $i < count($control_arr); $i++) {
        for ($j = 0; $j < count($mul_dim_arr); $j++) {
            if ($control_arr[$i] == $mul_dim_arr[$j][$sort_col]) {
                array_push($sorted_arr, $mul_dim_arr[$j]);
            }
        }
    }
    return $sorted_arr;
}

$test_arr = sort_mul_dim_arr($test_arr, 0);

After sorting, the output ($test_arr) would look like this:

$test_arr = [
    /* artist               albums  tracks */
    [ "Green Day",          "8",    "26",   ],
    [ "Linkin Park",        "6",    "18",   ],
    [ "Modern Talking",     "1",    "1",    ],
    [ "Remy Zero",          "1",    "2",    ],
    [ "Snow Patrol",        "1",    "2",    ],
    [ "System of a Down",   "1",    "1",    ],
];

But here's the problem. If the column I use to sort has unique values, function works fine. In the example, artist names are unique. But if I try to use albums or tracks columns to sort, function doesn't work. It messes up the array. Rows start to occur twice or more.

I have read some other questions about sorting multi-dimensional arrays, but they were talking about sorting in horizontal order. I need to sort in vertical order. How can I improve this function so I can sort with non-unique columns too? Or is there a PHP function to that already?

PHP Example

3 Answers 3

1

Some variation of this should work (array_column requires PHP >= 5.5.0). Sorts by tracks then albums then artist:

$artist = 0;
$albums = 1;
$tracks = 2;

array_multisort(
    array_column($test_arr, $tracks), SORT_DESC, 
    array_column($test_arr, $albums), SORT_DESC,
    array_column($test_arr, $artist), SORT_DESC,
    $test_arr
);

Here is a function that will do the same:

function sort_one_or_other(&$array, $sort1) {

    $sort2 = ($sort1 = 1) ? 2 : 1;

    array_multisort(
        array_column($array, $sort1), SORT_DESC, 
        array_column($array, $sort2), SORT_DESC,
        array_column($array, 0), SORT_DESC,
        $array
    );
}

sort_one_or_other($test_arr, 2);

print_r($test_arr);

If you really only care about one column with the others unsorted then:

function sort_by_col(&$array, $sort) {    
    array_multisort(array_column($array, $sort), SORT_DESC, $array);
}

sort_by_col($test_arr, 2);

print_r($test_arr);
Sign up to request clarification or add additional context in comments.

4 Comments

Is there a way to wrap this in a function and pass the column index to it? For example: sort_arr($main_arr, 0), 0 being the index for artists, 1 being the index for albums etc. I need a function to do sorting, because the sort order won't be fixed. I'll change it on the fly with JS. Since I'm not familiar with array_multisort and array_column, I don't know where to begin.
You state you want to sort by albums and tracks but you only want to pass one column into the function? How is that?
I want to pass a column index to a function that will sort the array by that index (column values) while keeping the the cells of the rows intact. In the example I gave in my question, the function I created does that. I pass an array and a column index. I have a table in my page and I'll be sorting the columns with clicks to table headers. The only thing that will be changing is the column I select to sort the array.
sort_by_col did the trick. Used SORT_ASC instead of SORT_DESC. Didn't need to sort the other columns since they sort ascending by default, which is what I'm using to sort. Thank you. This was very educational.
1

You can use usort(), like that:

<?php

function my_intcmp ($a, $b)
{
    $a = intval ($a);
    $b = intval ($b);
    if ($a == $b) {
        return 0;
    } else {
        return $a < $b ? 1 : -1;
    }
}

function my_sort ($a, $b)
{
    $comp1 = my_intcmp ($a[1], $b[1]);
    if ($comp1) {
        return $comp1;
    } else {
        return my_intcmp ($a[2], $b[2]);
    }
}

usort ($test_arr, "my_sort");
print_r ($test_arr);

?>

Comments

0

You can try something like below

$artist = array();$albums = array();$tracks = array();$finalArr = array();
foreach($test_arr as $k=>$v){$artist[] = $v[0];$albums[] = $v[1];$tracks[] = $v[2];}
$length = count($albums);
for($i = 0; $i < $length; $i++){
    for($j = $i + 1; $j < $length; $j++){
        if($albums[$i] < $albums[$j]){
            $temp = $albums[$j]; $tA = $artist[$j]; $tT = $tracks[$j];
            $albums[$j] = $albums[$i]; $artist[$j] = $artist[$i]; $tracks[$j] = $tracks[$i];
            $albums[$i] = $temp; $artist[$i] = $tA; $tracks[$i] = $tT;
        }
    }
}
foreach($albums as $k=>$v){ $finalArr[] = array('artist'=>$artist[$k], 'albums'=>$albums[$k], 'tracks'=>$tracks[$k]);}
print_r($finalArr);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.