Check matching times within an array

1

I'm working with an array of undefined arrays, where each array (child) has another grouping of indefinite schedules (with start and end time) for the execution of a given task, in the example below there are only two groupings of schedules for each child array, but within the execution of the system there can be several for both the number of schedules and the number of tasks.

The problem is ... How can I check if these times match in a "simpler" way without having to abuse recursion and loop repetitions? because in this system no task can be executed while another is running.

No timetable can be repeated, nor can it start in the time period of another set of times (start time and end time), and if there is at least one matching time, the check may stop.

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

Basically the scan 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 work 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"
  }
}

Note 2: If you can not escape loops, what would be the best practice?

Note 3: I can modify the array in any way, because it is only for verification, then it is discarded.

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

    
asked by anonymous 05.03.2017 / 01:04

1 answer

2

The logic is simple:

  • Traverses the list ( foreach ) - could be array_map ;
  • Converts the data to an object \DateTime ;
  • Checks if the interval does not match any previously checked (% with%); 3.1. If there is conflict, it throws the exception ( array_walk );
  • Adds the range in question to the list;
  • Returns the list of ranges;
  • Function \Exception :

    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 function return 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, with conflicting schedules:

    $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 handled.

    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;
      }
    }
    
        
    06.03.2017 / 14:03