Memochipan
Memochipan

Reputation: 3465

Order part of an array in PHP

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');

Upvotes: 1

Views: 932

Answers (2)

hakre
hakre

Reputation: 197682

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"
}

Upvotes: 0

Tim Lytle
Tim Lytle

Reputation: 17624

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]);
}

Upvotes: 2

Related Questions