Check coincident times within an array

Asked

Viewed 174 times

1

I’m working with a grouping of indefinite size of arrays, where each array (child) has another grouping of indefinite times (with initial and final times) for the execution of a given task, in the example below there are only two groupings of times for each child array, but within the execution of the system there may be several, both for the number of schedules, and for the number of tasks.

The problem is... How can I verify that these times coincide in a "simpler" way without having to abuse recursive and loop repetitions? because in this system no task can be executed while another one is running.

No schedule may be repeated, nor may it begin in the period of another set of times (initial and final time), and if there is at least one coincident time, the check may stop.

The rule between schedules is similar to a "human" "professional", which logically can not be in two places at the same time.

Basically the check should stop when: ($horario_inicial_atual >= $horario_inicial_anterior OR $horario_inicial_atual <= $horario_final_anterior) AND ($horario_final_atual >= $horario_inicial_anterior || $horario_final_atual <= $horario_final_anterior)

array(2) {
  [0]=>
  array(2) {
    [0]=>
    array(2) {
      ["initial"]=>
      string(5) "08:00"
      ["final"]=>
      string(5) "12:00"
    }
    [1]=>
    array(2) {
      ["initial"]=>
      string(5) "14:00"
      ["final"]=>
      string(5) "18:00"
    }
  }
  [1]=>
  array(2) {
    [0]=>
    array(2) {
      ["initial"]=>
      string(5) "08:00"
      ["final"]=>
      string(5) "12:00"
    }
    [1]=>
    array(2) {
      ["initial"]=>
      string(5) "14:00"
      ["final"]=>
      string(5) "18:00"
    }
  }
}

Note: If this previous list is too complicated to be worked for this check, this format can also be used:

array(4) {
  [0]=>
  array(2) {
    ["initial"]=>
    string(5) "08:00"
    ["final"]=>
    string(5) "12:00"
  }
  [1]=>
  array(2) {
    ["initial"]=>
    string(5) "14:00"
    ["final"]=>
    string(5) "18:00"
  }
  [2]=>
  array(2) {
    ["initial"]=>
    string(5) "08:00"
    ["final"]=>
    string(5) "12:00"
  }
  [3]=>
  array(2) {
    ["initial"]=>
    string(5) "14:00"
    ["final"]=>
    string(5) "18:00"
  }
}

Obs 2: In case there is no escape from loops, which would be the best practice?

Obs 3: I can modify the array anyway, because it is only for verification, then it is discarded.

Note 4: I just need to know if there are coincident times or not, without more details, the important thing is to know if it is true or false.

  • There won’t be much to escape from loops. Where does this data come from? Perhaps you can treat them on the database layer, making your life easier at the time of checking the conditions.

  • It comes directly from a user-created "calendar", this verification must occur before being saved to the bank.

1 answer

2


The logic is simple:

  1. Scroll down the list (foreach) - could be array_map;
  2. Converts the data to an object \DateTime;
  3. Checks if the range does not match any previously checked (array_walk); 3.1. If there is conflict, fire the exception (\Exception);
  4. Add the range in question to the list;
  5. Returns the range list;

Function schedule:

if (!function_exists('schedule'))
{
  /**
   * Retorna a lista de intervalos conforme a lista de entrada. Houvendo conflitos
   * nos horários, uma exceção é disparada.
   * 
   * @param  array  $items  Lista de intervalos de entrada
   * @return  array  Lista de intervalos de saída
   * @exception  \Exception  Quando houver conflitos nos intervalos
   */
  function schedule (array $items)
  {
    $_schedule = [];

    foreach ($items as $item)
    {
      $initial = \DateTime::createFromFormat("H:i", $item["initial"]);
      $final   = \DateTime::createFromFormat("H:i", $item["final"]);

      array_walk($_schedule, function ($value, $key) use ($initial, $final) {
        if (
          ($initial >= $value["initial"] && $initial <= $value["final"]) ||
          ($final >= $value["initial"] && $final <= $value["final"])
        )
        {
          throw new \Exception("{Mensagem de erro}");
        }
      });

      $_schedule[] = compact("initial", "final", [$initial, $final]);
    }

    return $_schedule;
  }
}

Examples

Example 1:

Considered a valid entry:

$data = [
  0 => [
    "initial" => "08:00",
    "final" =>"12:00",
  ],
  1 => [
    "initial" => "12:00",
    "final" =>"18:00",
  ]
];

The return of the function will be:

Array
(
    [0] => Array
        (
            [initial] => DateTime Object
                (
                    [date] => 2017-03-06 08:00:00.000000
                    [timezone_type] => 3
                    [timezone] => UTC
                )

            [final] => DateTime Object
                (
                    [date] => 2017-03-06 12:00:00.000000
                    [timezone_type] => 3
                    [timezone] => UTC
                )

        )

    [1] => Array
        (
            [initial] => DateTime Object
                (
                    [date] => 2017-03-06 12:00:00.000000
                    [timezone_type] => 3
                    [timezone] => UTC
                )

            [final] => DateTime Object
                (
                    [date] => 2017-03-06 18:00:00.000000
                    [timezone_type] => 3
                    [timezone] => UTC
                )

        )

)

Example 2:

Considered an invalid entry, time conflicting:

$data = [
  0 => [
    "initial" => "08:00",
    "final" =>"12:00",
  ],
  1 => [
    "initial" => "10:00",
    "final" =>"11:00",
  ]
];

The return of the function will be something like:

Uncaught Exception: {Mensagem de erro} in /run_dir/repl.php(68) : eval()'d code:26
Stack trace:
#0 [internal function]: {closure}(Array, 0)
#1 /run_dir/repl.php(68) : eval()'d code(28): array_walk(Array, Object(Closure))
#2 /run_dir/repl.php(68) : eval()'d code(48): schedule(Array)
#3 /run_dir/repl.php(68): eval()
#4 {main}
  thrown

If the exception is not dealt with.


Function returning true/false

if (!function_exists('schedule'))
{
  /**
   * Retorna a lista de intervalos conforme a lista de entrada. Houvendo conflitos
   * nos horários, uma exceção é disparada.
   * 
   * @param  array  $items  Lista de intervalos de entrada
   * @return  array  Lista de intervalos de saída
   * @exception  \Exception  Quando houver conflitos nos intervalos
   */
  function schedule (array $items)
  {
    $_schedule = [];

    foreach ($items as $item)
    {
      $initial = \DateTime::createFromFormat("H:i", $item["initial"]);
      $final   = \DateTime::createFromFormat("H:i", $item["final"]);

      try {
          array_walk($_schedule, function ($value, $key) use ($initial, $final) {
            if (
              ($initial >= $value["initial"] && $initial <= $value["final"]) ||
              ($final >= $value["initial"] && $final <= $value["final"])
            )
            {
              throw new \Exception("{Mensagem de erro}");
            }
          });
      } catch (\Exception $e) {
          return false;
      }

      $_schedule[] = compact("initial", "final", [$initial, $final]);
    }

    return true;
  }
}
  • It is possible to return a bool value instead of an Exception?

  • Just capture the exception within the function and return false. I added at the end of the reply.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.