The fact is that using a 2-dimensional array to store a rowspan for each cell, and if we do not need a cell, its size is zero.
And here is a sample code. You may need to sort your array first.
<?php $rows = array( array(2312, 'ABC', 'asda', 'sdf', 'dfg'), array(2312, 'ABCD', 'asd', 'fgd', 'ret'), array(2313, 'ABCD', 'asd', 'fgd', 'ret'), array(2455, 'XYZ', 'sdgg', 'rew', 'gdg'), ); function try_merge_col( &$rows, &$trs, &$tr, $row_i, $col_i ) { $row = $rows[$row_i]; $old = $rows[$row_i-1]; if( $row[$col_i] == $old[$col_i] ) { $tr[$col_i]=0; //throw it for( $k = $row_i-1; $k>=0; $k-- ) //from down to up { if( $trs[$k][$col_i] > 0 ) { //do merge $trs[$k][$col_i]++; break; } } } } function get_table( $rows ) { $ret = ""; $trs = array( array(1,1,1,1,1) ); //used to store cell size $last_row = null; for( $i = 1; $i < count($rows); $i++ ) { $this_tr = array(1,1,1,1,1); try_merge_col( $rows, $trs, $this_tr, $i, 0 ); //id try_merge_col( $rows, $trs, $this_tr, $i, 1 ); //name array_push( $trs, $this_tr ); } for( $i = 0; $i < count($rows); $i++ ) { $tr = $trs[$i]; $ret .= "<tr>"; for( $j=0 ; $j<5 ; $j++ ) { if( $tr[$j] >= 1 ) { if( $tr[$j] > 1 ) $ret .= "<td rowspan=\"".$tr[$j]."\">"; else $ret .= "<td>"; $ret .= $rows[$i][$j]; $ret .= "</td>"; } } $ret .= "</tr>"; } return $ret; } echo get_table( $rows ); ?>