1

I have this array:

array ('project'=>'My project','leader'=>'Michael Phepps','partner1'=>'John Campbell','partner2'=>'Phillip Prescott','agepartner1'=>25, 'agepartner2'=>'44', 'budget'=>'80000');

The array is the result of some queries in diferent tables: project table fields: project, leader, budget. partners fields: partner, age

The order of the array is defined by an user, and executed like this:

foreach ($userarray as $field) {loadField($field)};

As the operation is for each field I obtain 'partner2' after 'partner1' but I need to get 'agepartner1' after 'partner1', because them are displayed in a html table after that.

Any suggestions can I obtain:

array ('project'=>'My project','leader'=>'Michael Phepps','partner1'=>'John Campbell', 'agepartner1'=>25, 'partner2'=>'Phillip Prescott', 'agepartner2'=>'44', 'budget'=>'80000');
Michael Berkowski
  • 267,341
  • 46
  • 444
  • 390
Memochipan
  • 3,405
  • 5
  • 35
  • 60
  • possible duplicate of http://stackoverflow.com/questions/4896623/php-associative-array-key-order-not-sort – imm Oct 16 '11 at 02:30
  • 2
    Wouldn't it be easier if you just passed the entire array, and in whatever is outputting the HTML, just echo the right value? – Nathan Loding Oct 16 '11 at 02:57

2 Answers2

2

While perhaps not exactly the answer you're looking for, I think there may be a better way to approach your situation:

$data = array('key1' => 'is', 'key2' => 'test', 'key3' => 'This');
$order = array('key3', 'key1', 'key2');

foreach($order as $key){
  print_r($data[$key]);
}

Output:

This is test.

So with your data:

$userarray = array ('project'=>'My project',
                    'leader'=>'Michael Phepps',
                    'partner1'=>'John Campbell',
                    'partner2'=>'Phillip Prescott',
                    'agepartner1'=>25, 
                    'agepartner2'=>'44', 
                    'budget'=>'80000');

$order = array('project',
               'leader',
               'partner1', 
               'agepartner1', 
               'partner2', 
               'agepartner2', 
               'budget');

foreach($order as $field) {
  loadField($userarray[$field]);
}
Tim Lytle
  • 17,549
  • 10
  • 60
  • 91
  • Hi @Tim, Thanks for your answer. Your suggestion is great. I have a situation that complicate even more the exercise. I don't know how many partners each project will have. I know them after the sql query. – Memochipan Oct 16 '11 at 11:16
  • @Memochipan Then you can just create the order array once you have the results. Or, similar to how my example loops through *known* fields, you can loop through `partnerX` until you find on that's not set. – Tim Lytle Oct 16 '11 at 20:13
0

You can not directly order a part of an array. You can only divide your array into the parts you want to sort, then sort the parts, and then apply that sort on the array data. Because you can not change the positions of the keys as well. As Tim Lytle suggested, get the keys, sort them, then you have the solution. This reduces the problem a bit.

Naturally there is a solution for it. However, keep in mind that your data-structure is pretty awkward to sort. I did the following:

  • Get the keys
  • Categorize the keys: The category is the key itself if does not contain a number or it's the number if it contains a number.
  • Divide all keys into groups based on categories. That means, each time the category changes, a new group starts: ALPHA, DIGIT, ALPHA in your case.
  • Got through all groups and handle them. DIGIT groups might need sorting, so I sorted them (e.g. if agepartner comes before partner, I just did a a-z sort + reverse).
  • Flatten all parts into a key-array again. Key-sorting done.
  • Create a $sorted array based on the new key-order and the values from the original array.

In case you need to sort the numbers (e.g. first 1, then 2), you can sort each DIGIT group as well by key-sorting (ksort) the inner array. As your data-structure is that complex, the following code-example is with debug output and some comments, so it's at least a little bit easier for you to go through and to play with it:

$array = array ('project'=>'My project','leader'=>'Michael Phepps','partner1'=>'John Campbell','partner2'=>'Phillip Prescott','agepartner1'=>25, 'agepartner2'=>'44', 'budget'=>'80000');

// reduce the problem: If we can sort the keys, we have the solution.
$keys = array_keys($array);
echo "Keys:\n";
var_dump($keys);

// categorize keys: alpha-only or alpha and digits at the end
$categories = array();
foreach($keys as $key)
{
    $r = preg_match('/^([a-z]+)(\d*)$/', $key, $matches);
    assert('$r !== FALSE');
    list(,$alpha, $digits) = $matches;
    $category = $digits ? $digits : $alpha; 
    $categories[$category][] = $key;
}
echo "Categories:\n";
var_dump($categories);

// group categories together in their order: ALPHA blocks and DIGIT blocks
define('GROUP_ALPHA', 1);
define('GROUP_DIGIT', 2);
$last = GROUP_ALPHA;
$group = array(); // start with an empty group to add to, pointer
$groups = array(array(GROUP_ALPHA => &$group));
foreach($categories as $vkey => $category)
{
    $current = is_int($vkey) ? GROUP_DIGIT : GROUP_ALPHA;
    if ($current != $last)
    {
        // add new group
        unset($group);
        $group = array();
        $groups[] = array($current => &$group);
    }
    $group[] = $category;
    $last = $current;
}
unset($group); // remove pointer
echo "Groups:\n";
var_dump($groups);

// sort and flatten groups
$ungroup = array();
foreach($groups as $type => $group)
{
    if ($type == GROUP_DIGIT)
    {
        // if digit groups need to be sorted: partner, agepartner
        foreach($group as &$items)
        {
            sort($items);
            array_reverse($items);
            unset($items);
        }
    }
    // flatten the group
    $group = call_user_func_array('array_merge', $group);
    $group = call_user_func_array('array_merge', $group);
    $ungroup = array_merge($ungroup, $group);
}
echo "Un-Grouped:\n";
var_dump($ungroup);

// solve
$sorted = array();
foreach($ungroup as $key)
{
    $sorted[$key] = $array[$key];
}

echo "Sorted:\n";
var_dump($sorted);

Output:

Keys:
array(7) {
  [0]=>
  string(7) "project"
  [1]=>
  string(6) "leader"
  [2]=>
  string(8) "partner1"
  [3]=>
  string(8) "partner2"
  [4]=>
  string(11) "agepartner1"
  [5]=>
  string(11) "agepartner2"
  [6]=>
  string(6) "budget"
}
Categories:
array(5) {
  ["project"]=>
  array(1) {
    [0]=>
    string(7) "project"
  }
  ["leader"]=>
  array(1) {
    [0]=>
    string(6) "leader"
  }
  [1]=>
  array(2) {
    [0]=>
    string(8) "partner1"
    [1]=>
    string(11) "agepartner1"
  }
  [2]=>
  array(2) {
    [0]=>
    string(8) "partner2"
    [1]=>
    string(11) "agepartner2"
  }
  ["budget"]=>
  array(1) {
    [0]=>
    string(6) "budget"
  }
}
Groups:
array(3) {
  [0]=>
  array(1) {
    [1]=>
    array(2) {
      [0]=>
      array(1) {
        [0]=>
        string(7) "project"
      }
      [1]=>
      array(1) {
        [0]=>
        string(6) "leader"
      }
    }
  }
  [1]=>
  array(1) {
    [2]=>
    array(2) {
      [0]=>
      array(2) {
        [0]=>
        string(8) "partner1"
        [1]=>
        string(11) "agepartner1"
      }
      [1]=>
      array(2) {
        [0]=>
        string(8) "partner2"
        [1]=>
        string(11) "agepartner2"
      }
    }
  }
  [2]=>
  array(1) {
    [1]=>
    array(1) {
      [0]=>
      array(1) {
        [0]=>
        string(6) "budget"
      }
    }
  }
}
Un-Grouped:
array(7) {
  [0]=>
  string(7) "project"
  [1]=>
  string(6) "leader"
  [2]=>
  string(8) "partner1"
  [3]=>
  string(11) "agepartner1"
  [4]=>
  string(8) "partner2"
  [5]=>
  string(11) "agepartner2"
  [6]=>
  string(6) "budget"
}
Sorted:
array(7) {
  ["project"]=>
  string(10) "My project"
  ["leader"]=>
  string(14) "Michael Phepps"
  ["partner1"]=>
  string(13) "John Campbell"
  ["agepartner1"]=>
  int(25)
  ["partner2"]=>
  string(16) "Phillip Prescott"
  ["agepartner2"]=>
  string(2) "44"
  ["budget"]=>
  string(5) "80000"
}
hakre
  • 193,403
  • 52
  • 435
  • 836