Home > Software engineering >  3 arrays, preg_match and merge of the results in PHP
3 arrays, preg_match and merge of the results in PHP

Time:08-06

I have 3 different multidimensional arrays:

// INPUT DATA WITH HOUSE DESCRIPTION. STRUCTURE: ID, OPTION DESCRIPTION

$input_house_data = array (
array("AAA","Chimney with red bricks"),
array("BBB","Two wide windows in the main floor"),
array("CCC","Roof tiles renewed in 2015")
);

// CATALOGUE WITH ALL HOUSE EQUIPMENT OPTIONS. STRUCTURE: ID, OPTION NAME

$ct_all_house_options = array (
  array("0001","Chimney"),
  array("0002","Garden"),
  array("0003","Roof tiles"),
  array("0004","Windows"),
  array("0005","Garage")
);

// SEARCH STRINGS AS REGULAR EXPRESSIONS. STRUCTURE: ID, EQUIPMENT OPTION NAME, REGULAR EXPRESSION TO SEARCH

$ct_house_options = array (
  array("0001","Chimney","/^Chimney with./"),
  array("0003","Roof tiles","/^Roof tiles./"),
  array("0004","Windows","/.windows./"),
  array("0004","Windows","/.wide windows./")    
);

I would like to search within $input_house_data by use of the regular expressions from the array $ct_house_options in order to indicate which equipment has a house. The result should be the whole list with all possible options and status "available" or "not available":

0001 - Chimney - available
0002 - Garden - not available
0003 - Roof tiles - available
0004 - Windows - available
0005 - Garage - not available

I tried to realize it as following:

$arrlength_input_house_data = count($input_house_data);
$arrlength_ct_all_house_options = count($ct_all_house_options);
$arrlength_ct_house_options = count($ct_house_options);

For loop with preg_match function. All results are written into array $matches (including dublicates):

for ($row1 = 0; $row1 < $arrlength_input_house_data; $row1  ) {

   for ($row2 = 0; $row2 < $arrlength_ct_house_options; $row2  ) {
   
if (preg_match($ct_house_options[$row2][2], $input_house_data[$row1][1]) === 1) {
    $matches[] = $ct_house_options [$row2][0];
}
}
}

Deleting of dublicates:

$unique = array_unique($matches);
print_r($unique);

So now I have got the unique results:

Array ( [0] => 0001 [1] => 0004 [3] => 0003 )

The next step should be merge of the array $ct_all_house_options and unique results from $unique. Unfortunatelly I cannot get it zealized. Do you have any idea how to get it? Maybe is any more simple way to realize it?

CodePudding user response:

Loop through the array with all options. Check if the ID is in your $unique list, then it's available.

foreach ($ct_all_house_options as [$id, $name]) {
    if (in_array($id, $unique)) {
        echo "$id - $name - available<br>";
    } else {
        echo "$id - $name - not available<br>";
    }
}

CodePudding user response:

If performance is very important, you can prepare associative arrays to access the data faster. Here's a solution for the entire problem:

$optionsById = [];
foreach ($ct_house_options as $option) {
    $optionsById[$option[0]] = $option;
}

$availabilityById = [];
foreach ($ct_all_house_options as $option) {
    $id = $option[0];
    $availabilityById[$id] = false;
    foreach ($input_house_data as $data) {
        $option = $optionsById[$id] ?? null;
        if (!$option) {
            continue;
        }
        if (preg_match($option[2], $data['1'])) {
            $availabilityById[$id] = true;
            break;
        }
        
    }
}

foreach ($ct_all_house_options as $option) {
    $availabilityString = $availabilityById[$option[0]]
        ? 'available'
        : 'not available';
    echo "$option[0] - $option[1] - $availabilityString\n";
}

Performance:

  • Execution time:
    • min: 0.00000476837158203s
    • max: 0.00047588348388672s
    • avg: 0.0000226473808289s
  • Memory usage: 396KB

It's possible to do it with less code, though, if the foreach loop is changed:

$available = [];
foreach ($input_house_data as $data) {
    foreach ($ct_house_options as $option) {
        if (preg_match($option[2], $data['1'])) {
            $available[$option[0]] = true;
        }   
    }
}

foreach($ct_all_house_options as $option) {
    $availabilityString = isset($available)
        ? 'available'
        : 'not available';
    echo "$option[0] - $option[1] - $availabilityString\n";
}

Performance:

  • Execution time:
    • min: 0.00000691413879395s
    • max: 0.00018811225891113s
    • avg: 0.0000229740142822s
  • Memory usage: 396KB

If you still want to use the $unique, you can still prepare an associative array for performance reasons:

$indexById = array_flip($unique);
foreach ($ct_all_house_options as $option) {
    $availabilityString = isset($indexById[$option[0]])
        ? 'available'
        : 'not available';
    echo "$option[0] - $option[1] - $availabilityString\n";
}

Performance:

  • Execution time:
    • min: 0.00000905990600586s
    • max: 0.00018906593322754s
    • avg: 0.0000392961502075s
  • Memory usage: 397KB

Using in_array instead:

foreach ($ct_all_house_options as $option) {
    $availabilityString = in_array($option[0], $unique)
        ? 'available'
        : 'not available';
    echo "$option[0] - $option[1] - $availabilityString\n";
}
  • Execution time:

    • min: 0.0000100135803223s
    • max: 0.0050561428070068s
    • avg: 0.0000860285758972s
  • Memory usage: 396KB

I used PHP Sandbox to perform the tests. Of course, the execution time is not always the same.

  • Related