1

Consider the following multisort method. In this case I have a array of items with a specific start date. Example array is shown:

0 -> array('title' => 'hello',
             'attributes' => array('id' => 4, 'startdate' => '2013-06-11')),
1 -> array('title' => 'hello second entry',
             'attributes' => array('id' => 6, 'startdate' => '2013-04-11'))

You can see that the 2nd entry should come before the first. Using my call currently will not work because It only checks to depth 1 of the array.

$albums = $this->multiSort($items, "SORT_ASC", 'startdate', true);

How would be the best way to modify this method to have a depth search on the items in the array. Even better would be to be able to specific the depth key. I would like to avoid having to add additional parameters to the method.

I could call the method like so and then write a for loop to get the key data, but having nested for loops is not something I want to do.

$albums = $this->multiSort($items, "SORT_ASC", array('attributes', 'startdate') , true);

What is the best way to optimize this method for my case?

public function multiSort($data, $sortDirection, $field, $isDate) {

    if(empty($data) || !is_array($data) || count($data) < 2) {
        return $data;
    }

    foreach ($data as $key => $row) {
        $orderByDate[$key] = ($isDate ? strtotime($row[$field]) : $row[$field]);
    }

    if($sortDirection == "SORT_DESC") {
        array_multisort($orderByDate, SORT_DESC, $data);
    } else {
        array_multisort($orderByDate, SORT_ASC, $data);
    }

    return $data;
}
Sixthpoint
  • 1,161
  • 3
  • 11
  • 34
  • Duplicate: http://stackoverflow.com/questions/2699086/sort-multidimensional-array-by-value-2?rq=1 – DACrosby Sep 11 '13 at 19:45
  • @DACrosby It's not a duplicate... The OP has some specific requirements on inputs to the function that handles this. – Chris Rasco Sep 11 '13 at 19:48

1 Answers1

0

UPDATED. This allows you to pass in a string for field that is delimited and is a path to your desired field.

$items = Array();
$items[0] = array('title' => 'hello',
             'attributes' => array('id' => 4, 'startdate' => '2013-06-11'));
$items[1] = array('title' => 'hello second entry',
             'attributes' => array('id' => 6, 'startdate' => '2013-04-11'));

function multiSort($data, $sortDirection, $field, $isDate) {

    if(empty($data) || !is_array($data) || count($data) < 2) {
        return $data;
    }

    // Parse our search field path
    $parts = explode("/", $field);

    foreach ($data as $key => $row) {
        $temp = &$row;
        foreach($parts as $key2) {
            $temp = &$temp[$key2];
        }
        //$orderByDate[$key] = ($isDate ? strtotime($row['attributes'][$field]) : $row['attributes'][$field]);
        $orderByDate[$key] = ($isDate ? strtotime($temp) : $temp);
    }
    unset($temp);

    if($sortDirection == "SORT_DESC") {
        array_multisort($orderByDate, SORT_DESC, $data);
    } else {
        array_multisort($orderByDate, SORT_ASC, $data);
    }

    return $data;
}

$albums = multiSort($items, "SORT_ASC", 'attributes/startdate', true);
print_r($albums);

Ouput:

Array
(
    [0] => Array
        (
            [title] => hello second entry
            [attributes] => Array
                (
                    [id] => 6
                    [startdate] => 2013-04-11
                )

        )

    [1] => Array
        (
            [title] => hello
            [attributes] => Array
                (
                    [id] => 4
                    [startdate] => 2013-06-11
                )

        )

)
Chris Rasco
  • 2,713
  • 1
  • 18
  • 22
  • I would like to keep this method as flexible as possible. So I cannot guarantee that "attributes" will be available – Sixthpoint Sep 11 '13 at 20:27
  • You've got 2 constraints in the desire to avoid for loops and the desire to not add additional parameters. You could hijack the field parameter and pass in a "path". In our example you'd pass in something like "attributes/startdate" and explode it on the "/" and use that as your frame of reference for the sortable field. You'd still have to tweak do some work before calling array_multisort() though. – Chris Rasco Sep 11 '13 at 20:33
  • Ok i understand using $fields = explode("/", $field); to get the field list. But how would i use that to reference the entry? Do I have to convert the php array to a object? – Sixthpoint Sep 11 '13 at 21:55
  • this doesn't avoid the double for loop, but seeing I cant see a way around that for now. I will consider this good enough – Sixthpoint Sep 12 '13 at 02:34