views:

79

answers:

6

Is there anyway to order an array in this way? For example if I had this array:

$array = array("foo", "bar", "item", "item", "foo", "foo");

And I wanted to order it so that it was "foo", "foo", "foo", "item", "item", "bar" is there any way to do that?

+4  A: 

Would this do?

$array1 = array_count_values($array);
arsort($array1);
var_dump($array1);

will give you

array(3) {
  ["foo"]=>
  int(3)
  ["item"]=>
  int(2)
  ["bar"]=>
  int(1)
}

or do you necessarily need them as repeated values? if yes, you may go for something like:

usort($array,create_function('$a,$b',
    'return $GLOBALS["array1"][$a]<$GLOBALS["array1"][$b];'));

This is ugly code, but demonstrates the technique. It is also easy to make it good-looking with php 5.3 closures, but I don't know if you're on 5.3. That would look like this:

$acount=array_count_values($array = array("foo", "bar", "item", "item", "foo", "foo"));
usort($array,function($a,$b) use ($acount) { return $acount[$a]<$acount[$b]; });
Michael Krelin - hacker
Good call on array_count_values, I was just about to suggest that.
therefromhere
Short and sweet. I like it.
banzaimonkey
Awesome! Thanks!
WillyG
you're welcome. For the record, I've added the complete example with closure.
Michael Krelin - hacker
A: 

That's quite and unusual sort process, it would be simplest to do as a two or three step process.

First count the different objects, then sort the object counts and generate from that the sorted object array.

therefromhere
+1  A: 

usort() could work. array_count_values() comes in handy though. With the calculations you need to make, this might be a little more clear and efficient . If there are a lot of repeated values (100+), you may also want to consider using array_fill() instead of the for loop:

function getSortedGroupArray($array) {
  $return = array();
  $values = array_count_values($array);
  sort($values);
  foreach($values as $count => $value) {
    for($i = 0; $i < $count; ++$i) {
      $return[] = $value;
    }
  }
  return $return
}
AlReece45
+2  A: 

First you have to count occurrence of each value (array_count_values), then use usort to sort element by your criteria:

<?php

$array = array('foo', 'bar', 'bar', 'foo', 'bar', 'foo', 'foobar', 'foo', 'foo', 'foobar', 'bar', 'foo');

$tmp = array_count_values($array);
usort($array, function($e1, $e2) use($tmp) {
    return $tmp[$e2] - $tmp[$e1];
});

var_dump($array);
Crozin
A: 

Lets try this:

// First, lets count the number of objects  
$sort_by_term = array();
foreach($array as $string)
{
   if(isset($sort_by_term[$string]))
   {
       $sort_by_term[$string] += 1;
   }
   else
   {
       $sort_by_term[$string] = 1;
   }
}

// Next let's sort them by number
$sort_by_count = array();
foreach($sort_by_term as $term => $count)
{
    $sort_by_count[$count][] = $term;
}

// Now lets combine them
$final_array = array();
foreach($sort_by_count as $count => $term)
{
    while($count > 0)
    {
        $final_array[] = $term;
        $count -= 1;
    }
}

Could be shortened using some of PHP's functions, but you get the idea of what has to be done.

Chacha102
A: 

You can use the following function for ordering by the frequency with which a value appears in an array:

function array_count_sort(&$array, $direction = 1)
{
    // Could do with a better way of making $counts and $dir available to the
    // sorting function, but this will do for illustrative purposes.
    global $counts, $dir; 
    $counts = array_count_values($array);
    $dir = $direction;

    if (!function_exists('array_count_sort_cmp')) {
        function array_count_sort_cmp($a, $b) {
            global $counts, $dir;

            $c = $counts[$a];
            $d = $counts[$b];

            if ($c == $d) return 0;
            return ($c < $d) ? -$dir : $dir;
        }
    }

    usort($array, 'array_count_sort_cmp');
}

And use it in the following way:

$test = array("foo", "bar", "item", "item", "foo", "foo");
print_r($test);
array_count_sort($test);
print_r($test);
array_count_sort($test, -1);
print_r($test);

which would yield

Array
(
    [0] => foo
    [1] => bar
    [2] => item
    [3] => item
    [4] => foo
    [5] => foo
)
Array
(
    [0] => bar
    [1] => item
    [2] => item
    [3] => foo
    [4] => foo
    [5] => foo
)
Array
(
    [0] => foo
    [1] => foo
    [2] => foo
    [3] => item
    [4] => item
    [5] => bar
)
icio