Viewed   101 times

Currently I have some multidimensional arrays that look like this

Array ( 
    [71] => Array ( [author] => 2 [date] => 1392867376 ) 
    [49] => Array ( [author] => 2 [date] => 1392868188 ) 
    [75] => Array ( [author] => 14 [date] => 1392867388) 
    [67] => Array ( [author] => 2 [date] => 1392870805 ) 
)

I would like to sort them by the "date" but I have no idea how. I have tried this:

function cmp($a, $b) {
    if ($a == $b) {
        return 0;
    }
    return ($a < $b) ? -1 : 1;
}
uasort($visited, 'cmp');

But since I have no idea, and could not find a reference on how to use the "comparison function" I'm up in space. All I've been able to find was very vague stuff. Currently this sorts by "author".

Can someone kindly explain to me how these comparison functions work (or point me to an online resource) and tell me what I need to do to sort this array by "date" - while keeping all keys intact (keys must not be changed or erased)

Many thanks for any help provided.

PS: I have tried array_multisort - It erased my keys.

 Answers

1

try this cmp function:

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

It should work.

Thursday, August 25, 2022
4

Use usort like this:

$result = array();

$result[0]["prio"] = 1;
$result[0]["date"] = '2010-02-28';
$result[0]["post"] = "February's thoughts";

$result[1]["prio"] = 0;
$result[1]["date"] = '2010-04-20';
$result[1]["post"] = "April's thoughts";

$result[2]["prio"] = 0;
$result[2]["date"] = '2010-05-30';
$result[2]["post"] = "May's thoughts";

function fct($a ,$b) {

  if ($a['prio'] < $b['prio']) {
    return -1;
  } elseif  ($a['prio'] > $b['prio']) {
    return 1;
  } else {
    return strcmp($b['date'], $a['date']);
  }

}

usort($result, "fct");
print_r($result);

Output:

Array
(
    [0] => Array
        (
            [prio] => 0
            [date] => 2010-05-30
            [post] => May's thoughts
        )

    [1] => Array
        (
            [prio] => 0
            [date] => 2010-04-20
            [post] => April's thoughts
        )

    [2] => Array
        (
            [prio] => 1
            [date] => 2010-02-28
            [post] => February's thoughts
        )

)
Sunday, November 20, 2022
1

Use usort like so:

function myComp($a, $b) {
    if($a[1] == $b[1]) {
        return 0;
    }

    return ($a[1] > $b[1]) ? -1 : 1;
}

usort($myArray, 'myComp');
Sunday, October 2, 2022
 
3

I decided to rewrite my answer to accommodate both filtering and sorting. I took a heavily object oriented approach to solving this problem, which I will detail below.

You can see all of this code in action at this ideone.com live demonstration.


The first thing I did was define two interfaces.

interface Filter {
    public function filter($item);
}

interface Comparator {
    public function compare($a, $b);
}

As their names suggest, Filter is used for filtering, and Comparator is used for comparing.

Next, I defined three concrete classes that implements these interfaces, and accomplish what I wanted.

First is KeyComparator. This class simply compares the key of one element to the key of another element.

class KeyComparator implements Comparator {
    protected $direction;
    protected $transform;
    protected $key;

    public function __construct($key, $direction = SortDirection::Ascending, $transform = null) {
        $this->key = $key;
        $this->direction = $direction;
        $this->transform = $transform;
    }

    public function compare($a, $b) {
        $a = $a[$this->key];
        $b = $b[$this->key];

        if ($this->transform) {
            $a = $this->transform($a);
            $b = $this->transform($b);
        }

        return $a === $b ? 0 : (($a > $b ? 1 : -1) * $this->direction);
    }
}

You can specify a sort direction, as well as a transformation to be done to each element before they are compared. I defined a helped class to encapsulate my SortDirection values.

class SortDirection {
    const Ascending = 1;
    const Descending = -1;
}

Next, I defined MultipleKeyComparator which takes multiple KeyComparator instances, and uses them to compare two arrays against each other. The order in which they are added to the MultipleKeyComparator is the order of precedence.

class MultipleKeyComparator implements Comparator {
    protected $keys;

    public function __construct($keys) {
        $this->keys = $keys;
    }

    public function compare($a, $b) {
        $result = 0;

        foreach ($this->keys as $comparator) {
            if ($comparator instanceof KeyComparator) {
                $result = $comparator->compare($a, $b);

                if ($result !== 0) return $result;
            }
        }

        return $result;
    }
}

Finally, I created MultipleKeyValueFilter which is meant to filter an array based on an array of key/value pairs:

class MultipleKeyValueFilter implements Filter {
    protected $kvPairs;

    public function __construct($kvPairs) {
        $this->kvPairs = $kvPairs;
    }

    public function filter($item) {
        $result = true;

        foreach ($this->kvPairs as $key => $value) {
            if ($item[$key] !== $value)
                $result &= false;
        }

        return $result;
    }
}

Now, given the input array (Notice I rearranged them a bit to make the sorting obvious):

$array = array (
    '1' => array ('type' => 'blah2', 'category' => 'cat2', 'exp_range' => 'this_week' ),
    '2' => array ('type' => 'blah1', 'category' => 'cat1', 'exp_range' => 'this_week' ),
    '3' => array ('type' => 'blah1', 'category' => 'cat2', 'exp_range' => 'next_week' ),
    '4' => array ('type' => 'blah1', 'category' => 'cat1', 'exp_range' => 'next_week' )
);

Sorting can be achieved by doing the following:

$comparator = new MultipleKeyComparator(array(
    new KeyComparator('type'),
    new KeyComparator('exp_range')
));

usort($array, array($comparator, 'compare'));

echo "Sorted by multiple fieldsn";
print_r($array);

Filtering can be achieved by doing the following:

$filter = new MultipleKeyValueFilter(array(
    'type' => 'blah1'
));

echo "Filtered by multiple fieldsn";
print_r(array_filter($array, array($filter, 'filter')));

At this point I've given you a great deal of code. I'd suggest that your next step is to combine these two pieces into a single class. This single class would then apply both filtering and sorting together.

Monday, August 29, 2022
 
4pie0
 
5

You are right, the function you're looking for is array_multisort().

Here's an example taken straight from the manual and adapted to your case:

$price = array();
foreach ($inventory as $key => $row)
{
    $price[$key] = $row['price'];
}
array_multisort($price, SORT_DESC, $inventory);

As of PHP 5.5.0 you can use array_column() instead of that foreach:

$price = array_column($inventory, 'price');

array_multisort($price, SORT_DESC, $inventory);
Saturday, October 1, 2022
 
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :