jonathonh
jonathonh

Reputation: 153

Split an array of objects into groups of objects initialized by any encountered object of a specific instance

I have an array that looks like this:

array(
    0 => object //ticket,
    1 => object //user,
    2 => object //employee,
    3 => object //ticket,
    4 => object //user
    5 => object //ticket,
    6 => object //employee
);

From this you can see that the ticket object is always there, whereas the employee and user objects are each optional. What I'd like to do is loop through them and organize them like so:

array(
    [0] => array(
        [0] => object //ticket,
        [1] => object //user,
        [2] => object //employee,
    )
)

What I'm having trouble with is since the user and employee are optional I'm not sure how to correctly index based on the above model since occasionally I will hit one that doesn't have an employee or user (in the case that it doesn't, I'd want that index to be null). Any ideas?

EDIT: Example:

for ($i = 0; $i < count($result); $i++) {
    if ($result[$i] instanceof Ticket) {
        continue;
    } else {
        $newResult[$i][] = $result[$i]; //maybe I'm brainfarting, but cannot figure how to identify the last ticket index
    }
}

Upvotes: 0

Views: 86

Answers (4)

mickmackusa
mickmackusa

Reputation: 47991

To avoid needing to keep track of indexes or the size of the result array, maintain a reference array for each occurrence of a Ticket instance and push non-Ticket objects into the preceding reference array. Demo

class Ticket { }
class User { }
class Employee { }

$array = [
    new Ticket(),  // Ticket 1
    new User(),    // User 1
    new Employee(),// Employee 1
    new Ticket(),  // Ticket 2
    new User(),    // User 2
    new Ticket(),  // Ticket 3
    new Employee() // Employee 3
];

$result = [];
foreach ($array as $obj) {
    if ($obj instanceof Ticket) {
        unset($ref);
        $ref = [$obj];
        $result[] = &$ref;
    } else {
        $ref[] = $obj;
    }
}
var_export($result);

Output:

array (
  0 => 
  array (
    0 => 
    \Ticket::__set_state(array(
    )),
    1 => 
    \User::__set_state(array(
    )),
    2 => 
    \Employee::__set_state(array(
    )),
  ),
  1 => 
  array (
    0 => 
    \Ticket::__set_state(array(
    )),
    1 => 
    \User::__set_state(array(
    )),
  ),
  2 => 
  array (
    0 => 
    \Ticket::__set_state(array(
    )),
    1 => 
    \Employee::__set_state(array(
    )),
  ),
)

Upvotes: 0

Barmar
Barmar

Reputation: 781741

This is similar to your own answer, but doesn't require reindexing $newResult when it's done.

$newIndex = -1;
$newResult = array();
foreach ($result as $object) {
    if ($object instanceof Ticket) {
        $newResult[] = array($object);
        $newIndex++;
    } else {
        $newResult[$newIndex][] = $object;
    }
}

However, your original question mentioned setting the unused elements of the subarrays to null. Your answer doesn't do that, so I didn't either.

Upvotes: 1

jonathonh
jonathonh

Reputation: 153

Yeah, I definitely brainfarted. Sorry for wasting anyones time, here's the loop:

$lastTicketIndex = 0;
    for ($i = 0; $i < count($result) - 1; $i++) {
        if ($result[$i] instanceof Ticket) {
            $newResult[$i][] = $result[$i];
            $lastTicketIndex = $i;
            continue;
        } else {
            $newResult[$lastTicketIndex][] = $result[$i];
        }
    }

Upvotes: 0

paranoid
paranoid

Reputation: 535

You can check with instanceof which class' instance current array element is, and then group it as you prefer :)

Example

if( $array[0] instanceof ticket ) {
    // do some magic in here
}

http://php.net/manual/en/internals2.opcodes.instanceof.php

Upvotes: 0

Related Questions