Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sorting an array based on a condition

I have the following array

$records = array(

    array("postId"=>"1","grid"=>"6"),
    array("postId"=>"2","grid"=>"3"),
    array("postId"=>"3","grid"=>"6"),
    array("postId"=>"4","grid"=>"3"),
    array("postId"=>"5","grid"=>"3"),
    array("postId"=>"6","grid"=>"12"),
    array("postId"=>"7","grid"=>"3"),

);

I want to sort this array in a way that the sum of any number of back to back "grids" is equals to 12.

Example: The values of the "grids" in the above array are : 6,3,6,3,3,12,3

(6+6=12), (3+3+3+3=12),(12=12) so the new order should be 6,6,3,3,3,3,12 or 3,3,3,3,12,6,6 or 6,3,3,6,3,3,12

So after sorting the array the new array should look like following:

$records=array(

    array("postId"=>"1","grid"=>"6"),
    array("postId"=>"3","grid"=>"6"),
    array("postId"=>"2","grid"=>"3"),       
    array("postId"=>"4","grid"=>"3"),
    array("postId"=>"5","grid"=>"3"),
    array("postId"=>"7","grid"=>"3"),
    array("postId"=>"6","grid"=>"12"),

);

I searched in php manual and found these functions: sort,uasort, uksort, usort but I couldn't figure out how to use them.

Could you please tell me how to achieve this using PHP ?

Update

The value of grid will always be 3 or 6 or 12 (these three numbers only )

Problem

  $records = array(

    array("postId"=>"1","grid"=>"3"),
    array("postId"=>"2","grid"=>"6"),    
    array("postId"=>"3","grid"=>"3"),     
    array("postId"=>"4","grid"=>"3"),
    array("postId"=>"5","grid"=>"6"),
    array("postId"=>"6","grid"=>"6"),    
    array("postId"=>"7","grid"=>"3"),
    array("postId"=>"8","grid"=>"6"),

 );
like image 622
black_belt Avatar asked Mar 23 '23 07:03

black_belt


2 Answers

So you are not really sorting, but reordering to create sequence. I imagine that you are trying to do some layout of bricks with fixed height, and you need to have it reordered to fill each row and leave the rest at the end. With given fixed variants of 12,6,3 it can be done by sorting it in descending order - with odd number of sixes it will be filled with smaller threes. However such order will produce boring layout - to have it more interesting you only need to reorder some posts. For this you will need to create temporary container and merge it when sum of its grids is equal 12. If you are left with some temporary containers, merge them into one and sort descending before merging with previously grouped.

Code illustrating my concept:

//auxiliary function to calculate sum of grids in given temporary container
    function reduc($a) {
    return array_reduce($a, function ($result, $item) {
        return $result . $item['grid'] . ',';
    }, '');
}

function regroup($records, $group_sum = 12) {
    $temp = array();
    $grouped = array();

    foreach ($records as $r) {
        if ($r['grid'] == $group_sum) {
            $grouped[] = $r;
        } else {
            if (!$temp) {
                $temp[] = array($r);
            } else {
                $was_grouped = false;
                foreach ($temp as $idx => $container) {
                    $current_sum = sum_collection($container);
                    if ($current_sum + $r['grid'] <= $group_sum) {
                        $temp[$idx][] = $r;
                        if ($current_sum + $r['grid'] == $group_sum) {
                            $grouped = array_merge($grouped, $temp[$idx]);
                            unset($temp[$idx]);
                        }
                        $was_grouped = true;
                        break;
                    }
                }
                if (!$was_grouped) {
                    $temp[] = array($r);
                }
            }
        }
    }

    if ($temp) {
        //Sort descending, so biggest ones will be filled first with smalller
        $rest = call_user_func_array('array_merge', $temp);
        usort($rest, function($a, $b) {
            return $b['grid'] - $a['grid'];
        });
        $grouped = array_merge($grouped, $rest);
    }

    return $grouped;
}
like image 164
dev-null-dweller Avatar answered Mar 24 '23 23:03

dev-null-dweller


The question is:

I want to sort this array in a way that the sum of any number of back to back "grids" is equals to 12.

You may try this (using usort)

$records = array(
    array("postId"=>"1","grid"=>"6"),
    array("postId"=>"2","grid"=>"3"),
    array("postId"=>"3","grid"=>"6"),
    array("postId"=>"4","grid"=>"3"),
    array("postId"=>"5","grid"=>"3"),
    array("postId"=>"6","grid"=>"12"),
    array("postId"=>"7","grid"=>"3"),
);

You have number 34 times, nimber 6 2 times and number 12 once.

// Sort (ASC)
usort($records, function($a, $b) {
    return $a['grid'] - $b['grid'];
});

DEMO-1 (ASC) (3+3+3+3=12, 6+6=12, 12=12).

// Sort (DESC)
usort($records, function($a, $b) {
    return $b['grid'] - $a['grid'];
});

DEMO-2 (DESC) (12=12, 6+6=12, 3+3+3+3=12).

Output after sort using (ASC) :

Array (

[0] => Array
    (
        [postId] => 7
        [grid] => 3
    )

[1] => Array
    (
        [postId] => 5
        [grid] => 3
    )

[2] => Array
    (
        [postId] => 4
        [grid] => 3
    )

[3] => Array
    (
        [postId] => 2
        [grid] => 3
    )

[4] => Array
    (
        [postId] => 3
        [grid] => 6
    )

[5] => Array
    (
        [postId] => 1
        [grid] => 6
    )

[6] => Array
    (
        [postId] => 6
        [grid] => 12
    )

)

like image 29
The Alpha Avatar answered Mar 24 '23 22:03

The Alpha