Alessandro Minoccheri
Alessandro Minoccheri

Reputation: 35973

Group multidimensional data by one column and create subarrays in each group

I have a page into PHP where I retrieve XML data from a server and I want to store this data into an array.

This is my code:

foreach ($xml->DATA as $entry){
    foreach ($entry->HOTEL_DATA as $entry2){
        $id = (string)$entry2->attributes()->HOTEL_CODE;
        $hotel_array2 = array();
        $hotel_array2['id'] = $entry2->ID;
            $hotel_array2['name'] = utf8_decode($entry2->HOTEL_NAME);
        $i=0;
        foreach($entry2->ROOM_DATA as $room){
            $room_array = array();
            $room_array['id'] = (string)$room->attributes()->CCHARGES_CODE;
            $hotel_array2['rooms'][$i] = array($room_array);

            $i++;
        }
            array_push($hotel_array, $hotel_array2);
        }
}

In this mode I have the array hotel_array which all hotel with rooms. The problem is that: into my XML I can have multiple hotel with same ID (the same hotel) with same information but different rooms. If I have an hotel that I have already inserted into my hotel_array I don't want to insert a new array inside it but I only want to take its rooms array and insert into the exisiting hotel. Example now my situation is that:

hotel_array{
      [0]{
           id = 1,
           name = 'test'
           rooms{
               id = 1
           }
      }
      [0]{
           id = 2,
           name = 'test2'
           rooms{
               id = 100
           }
      }
      [0]{
           id = 1,
           name = 'test'
           rooms{
               id = 30
           }
      }
}

I'd like to have this result instead:

hotel_array{
      [0]{
           id = 1,
           name = 'test'
           rooms{
               [0]{
                  id = 1
               }
               [1]{
                  id = 30
               }
           }
      }
      [0]{
           id = 2,
           name = 'test2'
           rooms{
               id = 100
           }
      }
}

How to create an array like this?

Upvotes: 1

Views: 100

Answers (4)

mickmackusa
mickmackusa

Reputation: 47894

To avoid keeping track of indexes in the result array and avoiding reindexing the result after looping, push a new reference into the result array for each unique id encountered. For subsequent encounters of an id, push into the reference's subarray.

$result = [];
foreach ($xml->DATA as $entry) {
    foreach ($entry->HOTEL_DATA as $entry2) {
        $id = (string)$entry2->attributes()->HOTEL_CODE;
        if (!isset($ref[$id])) {
            $ref[$id] = [
                'id' => $entry2->ID,
                'name' => utf8_decode($entry2->HOTEL_NAME),
                'rooms' => [],
            ];
            $result[] =& $ref[$id];
        }
        foreach ($entry2->ROOM_DATA as $room) {
            $ref[$id]['rooms'][] = ['id' => (string)$room->attributes()->CCHARGES_CODE];
        }
    }
}
var_export($result);

Upvotes: 0

Stanislav Terletskyi
Stanislav Terletskyi

Reputation: 2112

And this :)

$hotel_array = array();

foreach ($xml->DATA as $entry)
{
    foreach ($entry->HOTEL_DATA as $entry2)
    {
        $hotel_code = (string) $entry2->attributes()->HOTEL_CODE;

        if (false === isset($hotel_array[$hotel_code]))
        {
            $hotel = array(
                'id' => $entry2->ID,
                'code' => $hotel_code,
                'name' => utf8_decode($entry2->HOTEL_NAME)
            );

            foreach($entry2->ROOM_DATA as $room)
            {
                $hotel['rooms'][] = array(
                    'id' => (string)$room->attributes()->CCHARGES_CODE,
                );
            }

            $hotel_array[$hotel_code] = $hotel;
        }
    }
} 

Upvotes: 0

Pebbl
Pebbl

Reputation: 36005

Whilst this is the similar answer to DevZer0 (+1), there is also quite a bit that can be done to simplify your workings... there is no need to use array_merge for one, or be specific about $i within your rooms array.

$hotels = array();
foreach ($xml->DATA as $entry){
  foreach ($entry->HOTEL_DATA as $entry2){
    $id = (string) $entry2->attributes()->HOTEL_CODE;
    if ( empty($hotels[$id]) ) {
      $hotels[$id] = array(
        'id' => $id,
        'name' => utf8_decode($entry2->HOTEL_NAME),
        'rooms' => array(),
      );
    }
    foreach($entry2->ROOM_DATA as $room){
      $hotels[$id]['rooms'][] = array(
        'id' => (string) $room->attributes()->CCHARGES_CODE;
      );
    }
  }
}

Just in case it helps...

Upvotes: 1

DevZer0
DevZer0

Reputation: 13535

first thing is it helps to keep the hotel id as the index on hotel_array when your creating it.

foreach ($xml->DATA as $entry){
    foreach ($entry->HOTEL_DATA as $entry2){
        $id = (string)$entry2->attributes()->HOTEL_CODE;
        $hotel_array2 = array();
        $hotel_array2['id'] = $entry2->ID;
            $hotel_array2['name'] = utf8_decode($entry2->HOTEL_NAME);
        $i=0;
        foreach($entry2->ROOM_DATA as $room){
            $room_array = array();
            $room_array['id'] = (string)$room->attributes()->CCHARGES_CODE;
            $hotel_array2['rooms'][$i] = array($room_array);

            $i++;
        }
            if (!isset($hotel_array[$hotel_array2['id']])) {
                  $hotel_array[$hotel_array2['id']] = $hotel_array2;
            } else {
                  $hotel_array[$hotel_array2['id']]['rooms'] = array_merge($hotel_array[$hotel_array2['id']]['rooms'], $hotel_array2['rooms']);
            }
        }
}

Upvotes: 2

Related Questions