Iterate through a 2d boolean array and leave only the largest adjacent β€œ2D block”,

Okay, so the question is awkwardly worded, but I hope this clarifies the situation.

I have this sample 2d array.

$array = array(
array(1, 0, 0, 0, 1, 0, 0, 1),
array(0, 0, 1, 1, 1, 1, 0, 1),
array(0, 1, 1, 0, 1, 0, 0, 0),
array(0, 1, 1, 0, 0, 0, 1, 0),
array(1, 0, 0, 0, 1, 1, 1, 1),
array(0, 1, 1, 0, 1, 0, 1, 0),
array(0, 0, 0, 0, 0, 0, 0, 1)
);

When it repeats with lines (and ends each line with \ n), and for each line, iterating through the column, it will repeat something like this: (β–‘β–‘ = 0, β–“β–“ = 1)

    β–“β–“β–‘β–‘β–‘β–‘β–‘β–‘β–“β–“β–‘β–‘β–‘β–‘β–“β–“
    β–‘β–‘β–‘β–‘β–“β–“β–“β–“β–“β–“β–“β–“β–‘β–‘β–“β–“
    β–‘β–‘β–“β–“β–“β–“β–‘β–‘β–“β–“β–‘β–‘β–‘β–‘β–‘β–‘
    β–‘β–‘β–“β–“β–“β–“β–‘β–‘β–‘β–‘β–‘β–‘β–“β–“β–‘β–‘
    β–“β–“β–‘β–‘β–‘β–‘β–‘β–‘β–“β–“β–“β–“β–“β–“β–“β–“
    β–‘β–‘β–“β–“β–“β–“β–‘β–‘β–“β–“β–‘β–‘β–“β–“β–‘β–‘
    β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–“β–“

But what I would like to do is to "parse" the array and leave only one adjacent form (the one that contains most of the "cells"), in this example the result would be:

    β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–“β–“β–‘β–‘β–‘β–‘β–‘β–‘
    β–‘β–‘β–‘β–‘β–“β–“β–“β–“β–“β–“β–“β–“β–‘β–‘β–‘β–‘
    β–‘β–‘β–“β–“β–“β–“β–‘β–‘β–“β–“β–‘β–‘β–‘β–‘β–‘β–‘
    β–‘β–‘β–“β–“β–“β–“β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘
    β–“β–“β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘
    β–‘β–‘β–“β–“β–“β–“β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘
    β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘

My initial approach was as follows:

  • Assign a unique number to each β–“β–“-cell (whether it is completely random or the current iteration number):

    01      02    03
        04050607  08
      0910  11      
      1213      14  
    15      16171819
      2021  22  23  
                  24
    
  • , : , β–“β–“ . , . :

    01      21    08
        21212121  08
      2121  21      
      2121      24  
    21      24242424
      2121  24  24  
                  24
    

    . , , , , 0, .

, , , . , !

BONUS POINTS: 2D-, , - blob,

+4
3

:

  • . 2 nΒ², , . , .

  • , , . /. : , , . ( -). .

+1

, . , , , . , 8 , , , ...

<?php 
$shape_nr=1;
$ln_max=count($array);
$cl_max=count($array[0]);
$done=[];

//LOOP ALL CELLS, GIVE 1 unique number
for($ln=0;$ln<$ln_max;++$ln){
for($cl=0;$cl<$cl_max;++$cl){
    if($array[$ln][$cl]===0)continue;
    $array[$ln][$cl] = ++$shape_nr;
}}

//DETECT SHAPES
for($ln=0;$ln<$ln_max;++$ln){
for($cl=0;$cl<$cl_max;++$cl){
    if($array[$ln][$cl]===0)continue;

    $shape_nr=$array[$ln][$cl];
    if(in_array($shape_nr,$done))continue;

    look_around($ln,$cl,$ln_max,$cl_max,$shape_nr,$array);
    //SET SHAPE_NR to DONE, no need to look at that number again
    $done[]=$shape_nr;
}}  

//LOOP THE ARRAY and COUNT SHAPENUMBERS
$res=array();
for($ln=0;$ln<$ln_max;++$ln){
for($cl=0;$cl<$cl_max;++$cl){
    if($array[$ln][$cl]===0)continue;
    if(!isset($res[$array[$ln][$cl]]))$res[$array[$ln][$cl]]=1;
    else $res[$array[$ln][$cl]]++;
}}

//get largest shape
$max = max($res);
$shape_value_max = array_search ($max, $res);

//get smallest shape
$min = min($res);
$shape_value_min = array_search ($min, $res);

// recursive function: detect connecting cells  
function look_around($ln,$cl,$ln_max,$cl_max,$nr,&$array){
    //create mini array
    $mini=mini($ln,$cl,$ln_max,$cl_max);
    if($mini===false)return false;

    //loop surrounding cells
    foreach($mini as $v){
        if($array[$v[0]][$v[1]]===0){continue;}
        if($array[$v[0]][$v[1]]!==$nr){
            // set shape_nr of connecting cell
            $array[$v[0]][$v[1]]=$nr;

            // follow the shape
            look_around($v[0],$v[1],$ln_max,$cl_max,$nr,$array);
            }
        }
    return $nr;
    }

// CREATE ARRAY WITH THE 9 SURROUNDING CELLS
function mini($ln,$cl,$ln_max,$cl_max){
    $look=[];   
    $mini=[[-1,-1],[-1,0],[-1,1],[0,-1],[0,1],[1,-1],[1,0],[1,1]];
    foreach($mini as $v){
        if( $ln + $v[0] >= 0 &&
            $ln + $v[0] < $ln_max &&
            $cl + $v[1] >= 0 &&
            $cl + $v[1] < $cl_max
            ){
            $look[]=[$ln + $v[0], $cl + $v[1]];
            }
        }

    if(count($look)===0){return false;}
    return $look;
    }

+1

If the size of your array is small and memory will not be a problem, perhaps a recursive solution will be faster. I found a C ++ algorithm that does this here: https://www.geeksforgeeks.org/find-length-largest-region-boolean-matrix/

0
source

Source: https://habr.com/ru/post/1693585/


All Articles