panthro
panthro

Reputation: 24061

Move specific array items to beginning of array without altering order of the rest

I have an array:

Array
(
    [product1] => Array
    (
        [id] => 1
        [title] => 'p1'
        [extra] => Array(
            [date] => '1990-02-04 16:40:26'
        )
    )

    [product2] => Array
    (
        [id] => 2
        [title] => 'p2'
        [extra] => Array(
            [date] => '1980-01-04 16:40:26'
        )
    )
    [product3] => Array
    (
        [id] => 3
        [title] => 'p3'
        [extra] => Array(
            [date] => '2000-01-04 16:40:26'
        )
    )
    [product4] => Array
    (
        [id] => 4
        [title] => 'p4'
        [extra] => Array(
            [date] => '1995-01-04 16:40:26'
        )
    )
    [product5] => Array
    (
        [id] => 5
        [title] => 'p5'
        [extra] => Array(
            [date] => '1960-01-04 16:40:26'
        )
    )
    ...

I need to get 2 products with the latest date and move them to the start of the array.

I've looked into the multisort function, and I could sort the array like this, but then the entire array would be arranged by date, I want to maintain the order of the array but just bump up the latest 2 rows.

I need to pick out the 2 latest (order by date) from the array, then move these to the start of the array. So the order of the ids should be:

3,4,1,2,5

The latest 2 have been moved to the front of the array, the remainder are still ordered by id.

Upvotes: 5

Views: 192

Answers (3)

deceze
deceze

Reputation: 522032

Not the most optimal implementation, but the most straight forward:

$array = /* your data */;

$latest = $array;
uasort($latest, function (array $a, array $b) {
    return strtotime($a['extra']['date']) - strtotime($b['extra']['date']);
});
array_splice($latest, 2);

$latestOnTop = array_merge($latest, array_diff_key($array, $latest));

The array_splice operation requires that your array keys are actually product1 or similar; won't work with numeric indices, as they'll be renumbered. Use another truncation mechanism if that's the case.

If your array is really big, a complete sort will be unnecessarily slow. In that case, you should rather loop over the array once, keeping track of the two latest items (and their keys) you could find, then array_diff_key and array_merge on that. That's a bit more difficult to implement (left as exercise for the reader), but much more efficient.

Upvotes: 1

viral
viral

Reputation: 3743

// copy current array for new array
$temp = $input; 

// sort temp array by latest date
uasort($temp, function($a,$b) {
    return (strtotime($a['extra']['date']) < strtotime($b['extra']['date']));
});

// for 2 key value pairs to get on top
$sorted_keys = array_keys($temp);

// initialize your required array
$final = [];

// two keys to move on top
$final [ $sorted_keys[0] ] = $temp [ $sorted_keys[0] ];
$final [ $sorted_keys[1] ] = $temp [ $sorted_keys[1] ];

foreach ($input as $k => $v)
{
    // insert your other array values except two latest
    if(!array_key_exists($k, $final))
    {
        $final[$k]=$v;
    }
}

unset($temp); // free up resource

$final is your required array

Upvotes: 0

splash58
splash58

Reputation: 26153

// Making array with only dates
$dates = array();
foreach ($arr as $key => $item) 
    $dates[$key] = $item['extra']['date'];
// Sort it by date saving keys
uasort($dates, function($i1, $i2) { return  strtotime($i1) - strtotime($i2); });
// Take keys
$dates = array_keys($dates);
// Create array with two needed items
$newarray = array( $dates[0] => $arr[$dates[0]], $dates[1] => $arr[$dates[1]]);
// remove these items
unset($arr[$dates[0]]);  unset($arr[$dates[1]]); 
// put them in array start
$arr = array_merge($newarray, $arr);
var_dump($arr);     

Upvotes: 0

Related Questions