Amy Neville
Amy Neville

Reputation: 10621

Reorder multidimensional array by list of IDs

I have a multidimensional array that is from a JSON API:

{
    "status": "success",
    "data": [
        {
            "id": 7,
            "anchor": "Atkins Diet Coupon",
            "status": "viewed",
            "points": 0,
            "latest_date": 1432135046,
            "created_date": 1432134221,
            "contacted": true
        },
        {
            "id": 6,
            "anchor": "Videostripe",
            "status": "viewed",
            "points": 0,
            "latest_date": 1432134545,
            "created_date": 1432131231,
            "contacted": false
        },
        {
            "id": 1,
            "anchor": "Smilebox",
            "status": "viewed",
            "points": 0,
            "latest_date": 1432053140,
            "created_date": 1432131131,
            "contacted": false
        }
    ]
}

I convert it using the following PHP code:

$data = file_get_contents($api_url);
$data = json_decode($data, true);

I have a list of ids that I want to have displayed first in the multidimensional array:

$ids = array('1','6');

So in this example: the multidimensional array would be reordered with 1,6,7 based on the order of the ids array, and then reverting back to its original order if not featured in the ids array.

This is a very complicated thing and I'm not sure at all how to do it!

Upvotes: 0

Views: 97

Answers (5)

prateekkathal
prateekkathal

Reputation: 3582

This I believe is a cleaner code :)

$ids = [1,6];

sort($ids); // Optional (For cases where you mistakenly write [1,7,6])

usort($data, function($a, $b) {
  return $a['id'] > $b['id'];
});

$ordered = array_filter($data, function($arrayData) use ($ids) {
  return (in_array($arrayData['id'], $ids));
});

$unordered = array_filter($data, function($arrayData) use ($ids) {
  return (!in_array($arrayData['id'], $ids));
});

$finalArray = array_merge($ordered, $unordered);

Glad to help :)

Upvotes: 1

sevavietl
sevavietl

Reputation: 3792

You can map the data to the ids. Then loop over $ids and grab the corresponded data in order of id appearance in the array, also unset founded $data elements. Then append the elements left in the $data to the end of the array containing founded elements.

$data = array_combine(
    array_column($response['data'], 'id'),
    $response['data']
);

$keyed = array_map(function ($id) use (&$data) {
    if (isset($data[$id])) {
        $datum = $data[$id];
        unset($data[$id]);

        return $datum;
    }

    return null;
}, $ids);

$data = array_values($keyed + $data);

Here is demo.

Note that when there's no element with te given id the null values will be placed.

Upvotes: 0

Ruslan Osmanov
Ruslan Osmanov

Reputation: 21502

$result = [];

// Convert the values into keys for convenience.
// It is easy to check if ID exists with isset($keys[$id]).
$keys = array_flip($ids);

// Collect items $ids
foreach ($ids as $id) {
  // Search for an item with this ID
  foreach ($data['data'] as $item) {
    if ($item['id'] == $id) {
      $result []= $item;
      break;
    }
  }
}

// Collect the rest of the items
foreach ($data['data'] as $item) {
  if (!isset($keys[$item['id']]))
    $result []= $item;
}

Upvotes: 0

Azeez Kallayi
Azeez Kallayi

Reputation: 2642

You can create another array with first values from your ID array and then other elements. You can create a custom function to get the key of the element from the array associated with the value of ID . Below code may help you. This is not fixed for (1,6). This is general solution. You can put any order, any number of elements.

<?php
 $data = '{
"status": "success",
"data": [
    {
        "id": 7,
        "anchor": "Atkins Diet Coupon",
        "status": "viewed",
        "points": 0,
        "latest_date": 1432135046,
        "created_date": 1432134221,
        "contacted": true
    },
    {
        "id": 6,
        "anchor": "Videostripe",
        "status": "viewed",
        "points": 0,
        "latest_date": 1432134545,
        "created_date": 1432131231,
        "contacted": false
    },
    {
        "id": 1,
        "anchor": "Smilebox",
        "status": "viewed",
        "points": 0,
        "latest_date": 1432053140,
        "created_date": 1432131131,
        "contacted": false
    }
]
}';

Convert to array, create ids array,initialize a reorder array

$data = json_decode($data, true);
$ids= array(1,6);
$array_elements = $data['data'];
$reordered_array=array();

Use foreach to fill the re-ordered array with the ids from the array.Use custom function to find the element. Remove the moved elements from the array. then merge them together.

foreach($ids as $id)
{
  $get_key =  mycustfunction($array_elements,'id',$id);
  $reordered_array[] = $array_elements[$get_key];
  unset($array_elements[$get_key]);
}
$result_array = array_merge($reordered_array,$array_elements);
print_r($result_array);

Custom function

function mycustfunction($products, $field, $value)
{
  foreach($products as $key => $product)
  {
     if ( $product[$field] === $value )
     return $key;
  }
  return false;
}

Upvotes: 0

fafl
fafl

Reputation: 7385

You can use usort to specify your own rules for sorting.

For example:

$ids = array('1','6');
usort($data["data"], function ($a, $b) use ($ids) {
    $pos_a = array_search($a['id'], $ids);
    $pos_b = array_search($b['id'], $ids);
    if ($pos_a === FALSE && $pos_b === FALSE) {
        return $a['id'] - $b['id'];
    }
    if ($pos_a === FALSE) {
        return 1;
    }
    if ($pos_b === FALSE) {
        return -1;
    }
    return $pos_a - $pos_b;
});
var_dump($data);

Upvotes: 1

Related Questions