How do I count and sort simple multidimensional array like this?

Greetings,

I have an array like this:


Array
(
[0] => Array
(
[userid] => 1
[name] => Joe1
)

[1] => Array
(
[userid] => 1
[name] => Joe1
)

[2] => Array
(
[userid] => 2
[name] => Joe2
)

[3] => Array
(
[userid] => 3
[name] => Joe3
)

[4] => Array
(
[userid] => 2
[name] => Joe2
)

[5] => Array
(
[userid] => 2
[name] => Joe2
)

)

The userid corresponds to a name. I would like to count up how many times the userid appears in the array. Then I would like to sort the array where the userid with the highest count appears first and desends. Basically this is what I want the array to look like:


Array
(
[0] => Array
(
[userid] => 2
[name] => Joe2
[count] => 3
)

[1] => Array
(
[userid] => 1
[name] => Joe1
[count] => 2
)

[2] => Array
(
[userid] => 3
[name] => Joe3
[count] => 1
)

)

Let me know how this can be done.

Thanks

I would use the userid as an array key, and walk the first array, adding to the new array’s counters.

Greetings StarLion,

I’m not too experienced when it comes to arrays or array keys, this is the first time I’ve messed around with arrays in PHP. Could you provide some sample code on how to do this or if you know the complete code to do this?

Thanks

Well lets see if you can take a stab yourself first.

You will need:
[FPHP]foreach[/FPHP]
Probably [FPHP]isset[/FPHP]
Always helps to brush up on your [FPHP]operators[/FPHP] (note the Unary Increment operator)
and for giggles [FPHP]array[/FPHP] definitions.

If you get stuck, don’t be afraid to ask further questions. StarLion isn’t trying to be mean, he really is trying to help. =p

Here is another hint: you’ll probably have to step through each element in the first array and construct a new array for the results.

[fphp]array_multisort[/fphp], though that array looks like a database result set. If it is you’re better served using the ORDER BY clause of the query to sort the results before the dB hands them over to PHP - this will be MUCH faster.

EDIT: Didn’t spot the counting, but it’s still a SQL problem


SELECT userid, COUNT(userid) AS `count`, name
FROM myTable
GROUP BY userid

This will be enormously faster than any PHP solution you can devise (presuming of course a database is the true source of the array).

I actually tried array_count_values() on a one dimensional array and it worked almost perfectly except it didn’t sort the highest count first and descend. Unfortunately, I can’t seem to get this working on a multidimensional array though. I’ve been trying to solve this for a few days now.

I was going to try the “foreach” loop but I still need to wrap my head around a system of doing this and then creating the new array. I will keep trying until someone else can figure it out.

Also, I’ve stored data results in my own array from a long series of independent SQL statements and loops that execute on the page, kind of like a count that records the userid and username whenever it shows up in the various loops. Then I want to show a grand total of sorts like above.

This is what I have so far, I’ve made the userid from the original array the array key:


$newarray = array();
foreach ($array as $key=>$value) {
   if($key == $newarray[$key]['userid']) {
	   $newarray[$key]['count'] = $newarray[$key]['count'] + 1;
   }
   else {
	   $newarray[$key] = array("userid" => $value['userid'], "name" => $value['name'], "count" => 1);
   }
}

It seems very close to working, the new array removes the duplicate user ids but it does not add to the count to reflect how many duplicates were found in the original array. I’m sure there is something simple, let me know what may be wrong.

Thanks


<?php
$users = array(
  array('id'  => 1, 'name'  => 'Bill'),
  array('id'  => 2, 'name'  => 'Bob'),
  array('id'  => 2, 'name'  => 'Bob'),
  array('id'  => 1, 'name'  => 'Bill'),
  array('id'  => 2, 'name'  => 'Bob'),
  array('id'  => 1, 'name'  => 'Bill'),
  array('id'  => 1, 'name'  => 'Bill'),
);

function aggregate($users){
  $aggregated = array();
  foreach($users as $user){
    if(!array_key_exists($user['id'], $aggregated)){
      $aggregated[$user['id']] = $user;
      $aggregated[$user['id']]['count'] = 0;
    }
    $aggregated[$user['id']]['count']++;
  }
  return $aggregated;
}

function sortByCount($a, $b){
  $a = $a['count'];
  $b = $b['count'];
  if($a === $b){
    return 0;
  }
  return $a < $b ? 1 : -1 ;
}

$users = aggregate($users);

usort($users, 'sortByCount');

print_r($users);

/*
  Array
  (
    [0] => Array
    (
      [id] => 1
      [name] => Bill
      [count] => 4
    )
    
    [1] => Array
    (
      [id] => 2
      [name] => Bob
      [count] => 3
    )
  )
*/

You haven’t clarified as to whether this data comes from a database though, if it does, you should use that to sort/group. :slight_smile:

[ot]hint: when posting array samples on which you would like help, use


$s = var_export( $your_array);
echo $s;

instead of var_dump(), which means we have to type it all out again, which is time consuming, which… well, you get the idea.
[/ot]

As Michael and Anthony pointed out, if it’s a DB result, consider using the query refinement suggested;

You were indeed very close on your attempt. Anthony’s code is pretty much what i’d do (I suggested you look at isset, he used array_key_exists, which takes the place of where i’d have used isset)

Thanks a lot Anthony, this really did the trick. I will continue studying this as I may need to take it a step further.

The data actually comes from Facebook’s FQL database. I’m learning how to build facebook apps so I can add it to my resume and improve my chances of finally getting a job! (I hope I don’t have to become as brilliant as Anthony to get a decent PHP job) I’ve done some good stuff with PHP/MySQL but FQL and arrays are things I haven’t worked with very often so this is great practice.