7

I have the following array:

$arr = [
    [
        'user_id' => 1,
        'product_id' => 1
    ],
    [
        'user_id' => 1,
        'product_id' => 2
    ],
    [
        'user_id' => 1,
        'product_id' => 3
    ],
    [
        'user_id' => 2,
        'product_id' => 1
    ],
    [
        'user_id' => 2,
        'product_id' => 2
    ],
    [
        'user_id' => 3,
        'product_id' => 1
    ]
];

And I want to sort it so it looks like this:

$arr = [
    [
        'user_id' => 1,
        'product_id' => 1
    ],
    [
        'user_id' => 2,
        'product_id' => 1
    ],
    [
        'user_id' => 3,
        'product_id' => 1
    ],
    [
        'user_id' => 1,
        'product_id' => 2
    ],
    [
        'user_id' => 2,
        'product_id' => 2
    ],
    [
        'user_id' => 1,
        'product_id' => 3
    ]
];

So basically I need to order by product_id and user_id in such a way that it selects the lower number product_id from each user before proceeding to the next.

I tried to use usort but I couldn't get it to work.

usort($campaigns, function($a, $b){
    if($a['product_id'] == $b['product_id']){
        return 0;
    }

    if($a['product_id'] < $b['product_id']){

        if($a['user_id'] == $b['user_id']){
            return 1;
        }

        if($a['user_id'] < $a['user_id']){
            return 0;
        }

        return -1;
    }else{

        if($a['user_id'] == $a['user_id']){
            return -1;
        }

        if($a['user_id'] < $a['user_id']){
            return 0;
        }

        return 1;
    }
});

I also tried array_multisort but all I could get it to do is to order using the same order that I already retrieve from the database.

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
Wern Ancheta
  • 22,397
  • 38
  • 100
  • 139
  • your code with `usort` is incorrect; you should compare to `<`/`>` by first field, and only if first fields are equals compare by second. – vp_arth Apr 12 '16 at 06:07
  • 2
    You are saying you are retrieving from database, any reason why you are not sorting directly on the query? – Salketer Apr 12 '16 at 06:09

3 Answers3

3

Assumption is your values is integers:

usort($campaigns, function($a, $b){
    if($a['product_id'] == $b['product_id']){
        return $a['user_id'] - $b['user_id'];
    } else {
        return $a['product_id'] - $b['product_id'];
    }
});

Also you can use database ordering with ORDER BY product_id, user_id clause.

vp_arth
  • 14,461
  • 4
  • 37
  • 66
2

Solution using array_multisort function with "array of columns"(few sorting dimensions):

$userIds = $productIds = [];
foreach ($arr as $k => $v) {
    $userIds[$k] = $v['user_id'];
    $productIds[$k] = $v['product_id'];
}

array_multisort($productIds, SORT_ASC, $userIds, SORT_ASC, $arr);

print_r($arr);

The output:

Array
(
    [0] => Array
        (
            [user_id] => 1
            [product_id] => 1
        )

    [1] => Array
        (
            [user_id] => 2
            [product_id] => 1
        )

    [2] => Array
        (
            [user_id] => 3
            [product_id] => 1
        )

    [3] => Array
        (
            [user_id] => 1
            [product_id] => 2
        )

    [4] => Array
        (
            [user_id] => 2
            [product_id] => 2
        )

    [5] => Array
        (
            [user_id] => 1
            [product_id] => 3
        )

)
RomanPerekhrest
  • 88,541
  • 4
  • 65
  • 105
1
$arrTags = [
    [
        'user_id' => 1,
        'product_id' => 1
    ],
    [
        'user_id' => 1,
        'product_id' => 2
    ],
    [
        'user_id' => 1,
        'product_id' => 3
    ],
    [
        'user_id' => 2,
        'product_id' => 1
    ],
    [
        'user_id' => 2,
        'product_id' => 2
    ],
    [
        'user_id' => 3,
        'product_id' => 1
    ]
];

foreach($arrTags as $key => $row){ 
$userArray[$key]  = $row['user_id'];
$productArray[$key] = $row['product_id'];
}

array_multisort($productArray, SORT_ASC, $userArray, SORT_ASC, $arrTags);
print_r($arrTags);

Output

 Array
(
    [0] => Array
        (
            [user_id] => 1
            [product_id] => 1
        )

    [1] => Array
        (
            [user_id] => 2
            [product_id] => 1
        )

    [2] => Array
        (
            [user_id] => 3
            [product_id] => 1
        )

    [3] => Array
        (
            [user_id] => 1
            [product_id] => 2
        )

    [4] => Array
        (
            [user_id] => 2
            [product_id] => 2
        )

    [5] => Array
        (
            [user_id] => 1
            [product_id] => 3
        )

)

You can also check in online editor. Click Here

RJParikh
  • 4,096
  • 1
  • 19
  • 36
  • Your output is not the same as OP's expected one. Also your comment about checking your answer is complete noise and useless. – Rizier123 Apr 12 '16 at 06:31
  • While this code snippet may solve the question, [including an explanation](http://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. Please also try not to crowd your code with explanatory comments, this reduces the readability of both the code and the explanations! – Rizier123 Apr 12 '16 at 06:32
  • Please check my edited code. I just forgot to chage $userArray and $productArray in multisort. I have edited code and output also checked in below linked editor. I am not brilliant and expert like you but I am trying my best to give useful answer to user. @Rizier123 – RJParikh Apr 12 '16 at 06:51
  • Sorry for inconvenience for this answer as I have attached output without checking its my fault. Mistake was interchanged of array in array_multisort($productArray, SORT_ASC, $userArray, SORT_ASC, $arrTags); @Rizier123 – RJParikh Apr 12 '16 at 06:54