ugsgknt
ugsgknt

Reputation: 115

Identifying duplicates in nested array on PHP

Look at the array shown below:

$eData = array (
  1 => 
  array (
    'title' => 'Title 01',
    'dates' => 
    array (
      2 => '2022-09-08',
      13 => '2022-08-17',
      14 => '2022-09-02',
    ),
  ),
  3 => 
  array (
    'title' => 'Title 02',
    'dates' => 
    array (
      2 => '2022-09-09',
      13 => '2022-09-02',
      14 => '2022-09-04',
    ),
  ),
  4 => 
  array (
    'title' => 'Title 03',
    'dates' => 
    array (
      2 => '2022-09-12',
      13 => '2022-09-03',
      14 => '2022-09-22',
    ),
  ),
  5 => 
  array (
    'title' => 'Title 04',
    'dates' => 
    array (
      2 => NULL,
      13 => '2022-09-04',
      14 => NULL,
    ),
  ),
  6 => 
  array (
    'title' => 'Title 05',
    'dates' => 
    array (
      2 => '2022-09-23',
      13 => '2022-09-05',
      14 => NULL,
    ),
  ),
  7 => 
  array (
    'title' => 'Title 06',
    'dates' => 
    array (
      2 => NULL,
      13 => '2022-09-06',
      14 => NULL,
    ),
  ),
  8 => 
  array (
    'title' => 'Title 07',
    'dates' => 
    array (
      2 => NULL,
      13 => NULL,
      14 => NULL,
    ),
  ),
  9 => 
  array (
    'title' => 'Title 08',
    'dates' => 
    array (
      2 => '2022-10-07',
      13 => '2022-09-08',
      14 => NULL,
    ),
  ),
)

Here I need to identify duplicate dates in nested dates array when it loop with foreach.

This is how I tried it in php:

$i=1;
$tdata = $e_des = $prevDate = $dateDup = '';
foreach ($eData as $eid => $eventData) {
  $e_title = $eventData['title'];

  $tdata .= "<tr>
              <td>{$i}</td>
              <td>
                <span>{$e_title}</span>
              </td>"; 


  foreach ($eventData['dates'] as $pid => $date) {
    if ($date) {
      $dateDup = $prevDate == $date ? ' text-danger' : ''; 
      $tdata .= "<td class='$dateDup'>$date</td>";
    } else {
      $tdata .= "<td>&nbsp;</td>";
    }
   
  }

  $tdata .= "</tr>";
  
  $prevDate = $date; 
  $i++;
}

This is only identifying one duplicate date and it is,

[3] => Array
        (
            [title] => Title 02
            [dates] => Array
                (
                    [13] => 2022-09-02
                )

        )

But, in my array, you can see there are four duplicate values (2022-09-02, 2022-09-04).

Can anybody help me, How to modify my code to identify all four duplicates in my array?

Upvotes: 1

Views: 70

Answers (2)

mickmackusa
mickmackusa

Reputation: 47894

Create a lookup array by collecting all dates, removing nulls, then counting occurrences with:

$lookup = array_count_values(array_filter(array_merge(...array_column($eData, 'dates'))));

Then while looping over your dates, check if the given date has occurred more than once.

$class = $lookup[$date] > 1 ? ' class="text-danger"' : '';

Here is my full re-scripting of your code:

Code: (Demo -- click on the eye icon to see the rendered HTML)

$lookup = array_count_values(array_filter(array_merge(...array_column($eData, 'dates'))));

$table = <<<HTML
<style> .text-danger { background-color: red; } </style>
<table border="1">
%s</table>
HTML;

$rowTemplate = <<<HTML
    <tr>
        <td>%d</td>
        <td>
            <span>%s</span>
        </td>%s
    </tr>

HTML;

$i = 1;
$html = '';
foreach ($eData as $id => $row) {
    $html .= sprintf(
        $rowTemplate,
        ++$i,
        $row['title'],
        array_reduce(
            $row['dates'],
            function ($result, $date) use($lookup) {
                if (!$date) {
                    $result .= "\n\t<td>&nbsp;</td>";
                } else {
                    $class = $lookup[$date] > 1 ? ' class="text-danger"' : '';
                    $result .= "\n\t<td$class>$date</td>";
                }
                return $result;
            },
            ''
        )
    );
}
if ($html) {
    printf($table, $html);
}

Upvotes: 1

MadCatERZ
MadCatERZ

Reputation: 185

Try this one:

$i = 1;
$existingDates = [];
$duplicates = [];
$tdata = $e_des = $prevDate = $dateDup = '';
foreach ($eData as $eid => $eventData) {
    foreach ($eventData['dates'] as $pid => $date) {
        if (!$date) {
            continue;
        }
        if (!isset($duplicates[$date])) {
            $duplicates[$date] = [];
        }
        
        $duplicates[$date][] = [$eid, $pid];    


    }
}
foreach ($duplicates as $date=>$possibleDuplicates) {
    if(count($possibleDuplicates)<2) {
        unset($duplicates[$date]);
    }
}
var_dump($duplicates);

Upvotes: 1

Related Questions