Aditya Kompella
Aditya Kompella

Reputation: 13

getting highest date in multidimensional array with id

Where the sub arrays have similar ids, I want to select only those with the highest date.

$array = [
           ['id' => 10, 'date' => '10-24-1994'],
           ['id' => 10, 'date' => '10-24-1996'],
           ['id' => 10, 'date' => '10-24-1997'],
           ['id' => 10, 'date' => '10-24-1998'],
           ['id' => 9, 'date' => '10-24-1998'],
           ['id' => 9, 'date' => '10-24-2001'],
           ['id' => 9, 'date' => '10-24-1997'],
           ['id' => 8, 'date' => '10-24-1996'],
           ['id' => 10, 'date' => '10-24-1999'],
           ['id' => 10, 'date' => '10-24-1991'],
           ['id' => 10, 'date' => '10-24-1993'],
           ['id' => 8, 'date' => '10-24-2001']
         ]; /* array i have */

$expected_Result = [
                     ['id' => 10, 'date' => '10-24-1999'],
                     ['id' => 9, 'date'=> '10-24-2001'],
                     ['id' => 8, 'date' => '10-24-2001'],
                   ];
 /* array which i expected */ 

Upvotes: 0

Views: 1266

Answers (6)

Chemaclass
Chemaclass

Reputation: 2011

I would use this as the solution, in order to have an array where the key is the id itself:

/** 
 * @param array{id:int, date:string} $list
 *
 * @return array<int,string> 
 */
function sortDatesUniqueById(array $list): array
{
    $result = [];

    foreach ($list as ['id' => $id, 'date' => $date]) {
        if (!isset($result[$id]) || $result[$id] < $date) {
            $result[$id] = $date;
        }
    }

    return $result;
}

Or another approach, to get exactly what you are asking for:

/** 
 * @param array{id:int, date:string} $list
 *
 * @return array{id:int, date:string} 
 */
function sortDatesUniqueById(array $list): array
{
    $result = [];

    foreach ($list as ['id' => $id, 'date' => $date]) {
        if (!isset($result[$id]) || $result[$id]['date'] < $date) {
            $result[$id] = ['id' => $id, 'date' => $date];
        }
    }

    return array_values($result);
}

PHPDoc used based on the standard https://github.com/phan/phan (generic arrays and array shapes).

Upvotes: 4

JesusValera
JesusValera

Reputation: 647

Here's my solution.

$result = [];

foreach ($array as $value) {
    if (!in_array($value['id'], array_column($result, 'id'))) {
        $result[] = $value;
    } else {
        foreach ($result as $key => $res) {
            if ($res['id'] === $value['id'] && $value['date'] < $res['date']) {
                $result[$key]['date'] = $value['date'];
            }
        }
    }
}

First iterate over each value, if it is not in the list, add to the $result var, else, iterate over the $result value and check when the id is the same whith the current $value and finally check wich date is bigger.

Upvotes: 1

Progrock
Progrock

Reputation: 7485

We can sort the array first by id and date ascending, and then use array_column to pull out the highest dates.

$array = [
    ['id' => 10, 'date' => '10-24-1994'],
    ['id' => 10, 'date' => '10-24-1996'],
    ['id' => 10, 'date' => '10-24-1997'],
    ['id' => 10, 'date' => '10-24-1998'],
    ['id' => 9, 'date' => '10-24-1998'],
    ['id' => 9, 'date' => '10-24-2001'],
    ['id' => 9, 'date' => '10-24-1997'],
    ['id' => 8, 'date' => '10-24-1996'],
    ['id' => 10, 'date' => '10-24-1999'],
    ['id' => 10, 'date' => '10-24-1991'],
    ['id' => 10, 'date' => '10-24-1993'],
    ['id' => 8, 'date' => '10-24-2001']
]; 

uasort($array, function($a, $b) {
    $r = $a['id'] <=> $b['id'];
    if($r == 0)
        return $a['date']<=>$b['date'];
    return $r;
});

var_export(array_column($array, null, 'id'));

Output:

array (
  8 => 
  array (
    'id' => 8,
    'date' => '10-24-2001',
  ),
  9 => 
  array (
    'id' => 9,
    'date' => '10-24-2001',
  ),
  10 => 
  array (
    'id' => 10,
    'date' => '10-24-1999',
  ),
)

Upvotes: 0

Rahul
Rahul

Reputation: 18557

Here is one liner,
First sort by id desc and date asc. Then make key as id so that last date of it will override every small dates. Then to reset index use array_values.

array_multisort(array_column($array, 'id'), SORT_DESC, array_column($array, 'date'), SORT_ASC, $array);
$result = array_values(array_column($array, null, "id"));
print_r($result);

array_column — Return the values from a single column in the input array

Note: column_key: The column of values to return. This value may be an integer key of the column you wish to retrieve, or it may be a string key name for an associative array or property name. It may also be NULL to return complete arrays or objects (this is useful together with index_key to reindex the array).

Demo

Output:-

Array
(
    [0] => Array
        (
            [id] => 10
            [date] => 10-24-1999
        )

    [1] => Array
        (
            [id] => 9
            [date] => 10-24-2001
        )

    [2] => Array
        (
            [id] => 8
            [date] => 10-24-2001
        )

)

Upvotes: 0

MH2K9
MH2K9

Reputation: 12039

You can user array_multisort() and finally array_walk() to make the array unique.

array_multisort(
    array_column($array, 'id'), SORT_DESC, 
    array_column($array, 'date'), SORT_DESC, 
    $array
);

$result = [];
array_walk($array, function ($item) use (&$result) {
    !isset($result[$item['id']]) && $result[$item['id']] = $item['date'];
});

print '<pre>';
print_r($result);

Upvotes: 0

Qirel
Qirel

Reputation: 26460

Just loop over the array, check if that ID exists as an index in the $result array. If it does, check if the new date is bigger than the current one - if yes, overwrite it with the new value.

$result = [];
foreach ($array as $v) {
    if (!isset($result[$v['id']])) {
        $result[$v['id']] = $v['date'];
    } elseif ($result[$v['id']] < $v['date']) {
        $result[$v['id']] = $v['date'];
    }
}

Upvotes: 2

Related Questions