PHP无法为任意长度的二维数组编写重新排序函数

Broadly speaking, I have a 2-dimensional array of the following format:

$elements = array(  0 => array('typeA', 'desc'),
                    1 => array('typeB', 'desc'),
                    2 => array('typeA', 'desc'),
                    n => array('typeC', 'desc'));

Where typeX can be 1 of 5 possibilities, and desc can be anything. The end goal is $elements sorted such that no two elements who share a typeX are ever adjacent. Here's my function:

function fixDbls($elems) {
    $final   = array();
    $singles = array();
    $doubles = array();
    $lastelem = null;
    foreach($elems as $elem) {
        if(!$lastelem) { // set this the first time through
            $lastelem = $elem[0];
            $singles[] = $elem;
        } else { //otherwise, sort!
            if($lastelem == $elem[0]) {
                $doubles[] = $elem;
            } else {
                $singles[] = $elem;
            }
        }
    }

    if ($doubles) {
            // I suspect this is where it all goes wrong, I am awful at recursion!
        $final = fixDbls(array_merge($singles, $doubles));
    } else {
        $final = $singles;
    }

    return $final;
}

If anyone can help me understand why this doesn't work (not just the code, but, where I've made a false assumption or where my thinking about this problem betrayed me—helps makes this more generally useful to the public!) I'd be ever, ever so appreciative.

I've been thinking your problem over and I think I came up with a solution. Here's the

code:

<?php

function print_array( $s, $a )
{
    echo $s.': { ';
    foreach ( $a as $k => $aa ) {
        echo $k.' => ';
        if ( is_array($aa) ) {
            echo '{ '.implode( ', ', $aa ).' }, ';
        } else {
            echo $aa.', ';
        }
    }
    echo '}'.PHP_EOL;
}

function search_array( array $a, $k )
{
    $found = false;
    foreach ( $a as $kk => $aa ) {
        if ( $aa[0] == $k ) {
            $found = $kk;
            break;
        }
    }

    return $found;
}

$input = array(  
        array('typeA', 'desc'),
            array('typeB', 'desc'),
                array('typeA', 'desc'),
                array('typeC', 'desc')
);

print_array( 'Initial input', $input );
$frequencies = array();

foreach ( $input as $e ) {
    $frequencies[ $e[0] ] = array_key_exists( $e[0], $frequencies ) ? $frequencies[ $e[0] ] + 1 : 1;
}

arsort($frequencies);

print_array( 'Frequencies', $frequencies );
$tail = array_slice( $frequencies, 1 );
$maxFreq = current( $frequencies ); 
$orderedElems = array_keys( $frequencies );
$mostFreq = current( $orderedElems );

echo 'The most frecuent element is "'.$mostFreq.'"'.PHP_EOL;

if ( array_sum( $tail ) < $maxFreq - 1 ) {
    die ('There\'s No possible solution'.PHP_EOL);
}

$ouput = array();

for ( $i = 0; $i < $maxFreq; $i++ ) {
    $k = search_array( $input, $mostFreq);
    $output[] = $input[ $k ];
    unset( $input[ $k ] );
}

print_array( 'Input after removing "'.$mostFreq.'"', $input );

echo '-----'.PHP_EOL;
print_array( 'Before process, output', $output );

foreach ( $tail as $e => $f ) {
    $i = 1;
    echo 'Elem to place: "'.$e.'" ('.$f.' times)'.PHP_EOL;
    while ( ( $k = search_array( $input, $e ) ) !== false ) {
        echo '$i: '.$i.PHP_EOL;
        $begin = array_slice( $output, 0, $i );
        print_array( 'Begin', $begin );
        $end = array_slice( $output, $i );
        print_array( 'End', $end );
        $output = array_merge( $begin, array( $input[$k] ), $end );
        print_array( 'Output', $output );
        $i+=2;
        unset( $input[$k] );
        echo PHP_EOL;
    }
}

print_array( 'Final output', $output );

This time I just tried the example you put in the question. The end result was:

Final output: { 0 => { typeA, desc }, 1 => { typeB, desc }, 2 => { typeC, desc }, 3 => { typeA, desc }, }

I hope this version suits your needs.

I made it a function now. This should work, the best.

$elements = array(0 => array('typeA', 'desc'), 1 => array('typeA', 'desc'), 2 => array('typeB', 'desc'), 3 => array('typeC', 'desc'), 4 => array('typeC', 'desc'), 5 => array('typeB', 'desc'), 6 => array('typeB', 'desc'), 7 => array('typeD', 'desc'), 8 => array('typeD', 'desc'), 9 => array('typeA', 'desc'), 10 => array('typeA', 'desc'));
function sortDeep($ary){
  foreach($ary as $a){
    foreach($a as $i => $v){
      if($i === 0)$typesArray[] = $v;
    }
  }
  function notNextTo($a, $b){
    if($a === $b){
      return 1;
    }
    else{
      return 0;
    }
  }
  uasort($typesArray, 'notNextTo'); $ak = array_keys($typesArray);
  foreach($ary as $i => $v){
    $sorted[$i] = $ary[$ak[$i]];
  }
  return $sorted;
}
print_r(sortDeep($elements));