【问题标题】:Small sorting algorithm in phpphp中的小排序算法
【发布时间】:2011-10-18 08:55:07
【问题描述】:

它应该很简单的算法,但我无法绕过它。

我有一些按字母顺序排列的数组

[0] => Array
    (
        [0] => a
        [1] => b
        [2] => c
    )

例如

[0] => Array
    (
        [0] => a
        [1] => b
        [2] => c
        [3] => d
    )

我需要将它们分类成行。例如:

我应该收到一个包含 3 列和尽可能多的行的表格,并且应该按字母顺序排列。

这是一个例子: 第一个数组应该转换成

[0] => Array
    (
        [0] => Array
            (
                [0] => a
                [1] => b
                [2] => c
            )

    )

但第二个应该是

[1] => Array
    (
        [0] => Array
            (
                [0] => a
                [1] => c
                [2] => d
            )
        [1] => Array
            (
                [0] => b
            )
    )

我写在php,如果有人能提供帮助,我将不胜感激。

统一更新: 代码示例:

function sortAsOrdered( array $categories )
{
    foreach ( $categories as $groupId => $group )
    {
        $regroupMenuItems = array();
        $limit            = count( $group );
        $rows             = ceil( $limit / 3 );

        for ( $i = 0; $i < $rows; ++$i )
        {
            $jumper = 0;

            for ( $j = 0; $j < 3; $j++ )
            {
                if ( 0 == $jumper )
                {
                    $jumper = $i;
                }

                if ( isset( $group[ $jumper ] ) )
                {
                    $regroupMenuItems[ $i ][ $j ] = $group[ $jumper ];
                }

                $jumper = $jumper + $rows;
            }
        }

        $categories[ $groupId ] = $regroupMenuItems;
    }

    return $categories;
}

伙计们,我解决了这个问题。在这里你可以看到我的算法http://pastebin.com/xe2yjhYW。 但不要难过,你的帮助不会白费。我可能会为那些帮助我解决这个困难算法的人提供赏金。

伙计们再感谢一次。您的想法启发了我以不同的方式思考。

【问题讨论】:

  • 在你的第二个结果中,它们不再按字母顺序排序,打破排序顺序的标准是什么?
  • 他似乎希望列按字母顺序排序
  • 我认为他希望按列排序,然后按行排序
  • @Marcus 如果您将它们作为列放在彼此的顶部,它们就是。
  • @Col。弹片,Paul Dixon 正是。

标签: php algorithm sorting


【解决方案1】:

array_chunk() 本来是解决方案,但由于您希望对其进行特殊排序,这对您没有多大帮助。

所以这是我的五分钱:

function array_chunk_vertical($input, $size_max) {
    $chunks = array();
    $chunk_count = ceil(count($input) / $size_max);

    $chunk_index = 0;
    foreach ($input as $key => $value) {
        $chunks[$chunk_index][$key] = $value;

        if (++$chunk_index == $chunk_count) {
            $chunk_index = 0;
        }
    }

    return $chunks;
}


$array = array('a', 'b', 'c', 'd', 'e', 'f');
var_dump(array_chunk_vertical($array, 2));

这会给你:

array
  0 => 
    array
      0 => string 'a' (length=1)
      3 => string 'd' (length=1)
  1 => 
    array
      1 => string 'b' (length=1)
      4 => string 'e' (length=1)
  2 => 
    array
      2 => string 'c' (length=1)
      5 => string 'f' (length=1)

这个函数的缺点是你只能告诉一个块中元素的最大数量,然后它将数组平均划分为块。因此,对于 [4] 和 max_size 3,您将得到 [2,2] 与预期的 [3,1] 不同。

【讨论】:

  • 这里预期的输出应该是第一列中的 [ab],第二列中的 [cd],第三列中的 [ef]。看起来您的解决方案是在第一行执行 [abc],在第二行执行 [def]。
  • @Ben:嗯,他的问题有点令人困惑,但如果他想要你说的方式,array_chunk() 应该可以正常工作。
  • 不完全,抱歉。如果你用这样的数组array( 'a', 'b', 'g', 'h' )尝试你的算法,你会得到array( [0] =&gt; array( 'a', 'g', ), [1] =&gt; array( 'b', 'h', ), )的结果,但我需要它是array( [0] =&gt; array( 'a', 'g', 'h', ), [1] =&gt; array( 'b', ), )
  • 抱歉,为了简单快速,算法不够智能,我重构了代码以反映这一点。稍后,一旦我对一些聪明的事情产生了灵感,我会添加一个更聪明的。
  • 他的函数接受第二个参数,指示应该有多少列。如果你打电话给array_chunk_vertical($array, 3));@Eugene,你想要的输出就会出现。
【解决方案2】:
<?php

$five_el = array('a', 'b', 'c', 'd', 'e');

$two_el = array('a', 'b');

$three_el = array('a', 'b', 'c');

$six_el = array('a', 'b', 'c', 'd', 'e', 'f');

function multid($sorted_array) {
    $mulidarray = array();
    $row = 0;
    $column = 0;
    foreach ($sorted_array as $value) {
        if ($column == 3) {
            $row++;
        }
        $column++;
        if (!isset($mulidarray[$row])) {
            $mulidarray[$row] = array();
        }
        $multidarray[$row][] = $value;
    }

    return $multidarray;
}

var_dump(multid($five_el));
var_dump(multid($two_el));
var_dump(multid($three_el));
var_dump(multid($six_el));

【讨论】:

  • 试试array( 'a', 'b', 'c', 'd' ),如果可以的话显示结果。我需要array( [0] =&gt; array( 'a', 'c', 'd' ), [1] =&gt; array( 'b' ) )
  • 答案是array( [0] =&gt; array( 'a', 'b', 'c'), [1] =&gt; array( 'd' ) )
  • 呵呵呵呵,我好像没看清楚这个问题。对不起!
【解决方案3】:

array_chunk 是解决问题的自然首选方法,但它不会完全满足您的需求。如果以这种方式提供解决方案,您需要在处理结果数组之前重新构造结果数组或重新构造输入,如下所示:

$input = range('a', 'k');  // arbitrary
$columns = 3;  // configure this
$rows = ceil(count($input) / $columns);

// fugly, but this way it works without declaring a function
// and also in PHP < 5.3 (on 5.3 you'd use a lambda instead)
$order = create_function('$i',
                         '$row = (int)($i / '.$rows.');'.
                         '$col = $i % '.$rows.';'.
                         'return $col * ('.$columns.' + 1) + $row;');

// $order is designed to get the index of an item in the original array,
// and produce the index that item would have if the items appeared in
// column-major order instead of row-major as they appear now
$array = array_map($order, array_keys($input));

// replace the old keys with the new ones
$array = array_combine($array, $input);

// sort based on the new keys; this will effectively transpose the matrix,
// if it were already structured as a matrix instead of a single-dimensional array
ksort($array);

// done!
$array = array_chunk($array, $columns);
print_r($array);

See it in action

【讨论】:

  • 不幸的是,这不适用于 range('a','d') - 他期待 (a,c,d)(b) - 你的脚本给出 (a,c,b)( d) :(
【解决方案4】:

让我们看看这是否更接近标记

function splitVerticalArrayIntoColumns($aInput, $iNumberOfColumns) {

  //output array
  $aOutput = array();

  //the total length of the input array
  $iInputLength = count($aInput);

  //the number of rows will be ceil($iInputLength / $iNumberOfColumns)
  $iNumRows = ceil($iInputLength / $iNumberOfColumns);

  for($iInputIndex = 0; $iInputIndex < $iInputLength; $iInputIndex++) {
    $iCurrentRow = $iInputIndex % $iNumRows;
    $aOutput[$iCurrentRow][] = $aInput[$iInputIndex];
  }

  //return
  return $aOutput;
}

Which - 当这样运行时:

$aList = array("a", "e", "d", "b", "c");
echo 'array("a", "e", "d", "b", "c")' . "\n\n";
print_r(splitVerticalArrayIntoColumns($aList, 3));

给予:

array("a", "e", "d", "b", "c")

Array
(
    [0] => Array
        (
            [0] => a
            [1] => d
            [2] => c
        )

    [1] => Array
        (
            [0] => e
            [1] => b
        )

)

这还没有对每一行进行排序,但这是你所追求的吗?



开始手掌编辑

...当然,array_chunk($aList, 3) 排序后 O_o

http://uk3.php.net/manual/en/function.array-chunk.php

我会将下面的所有内容留作参考或其他任何内容 - 我完全忘记了 array_chunk()

结束手掌编辑


我会在循环中使用模数来计算数组索引(在对数组进行排序之后) - 例如,如果您尝试将数组拆分为 3 个“列”,您可以尝试以下操作:

if($iIndex % 3 == 0) {
  //... create a new array
}
else {
  //... add to an existing array
}

编辑代码示例:

$aList = array("a", "e", "d", "b", "c");
sort($aList);

$iDesiredNumberOfColumns = 3;
$iListLength = count($aList);

$aListInColumns = array();
$iRowNumber = 0;

for($iIndex = 0; $iIndex < $iListLength; $iIndex++) {
  $iColumnNumber = $iIndex % 3;
  if($iIndex != 0 && $iColumnNumber == 0) {
    $iRowNumber++;
  }

  $aListInColumns[$iRowNumber][$iColumnNumber] = $aList[$iIndex];
}

刚刚在我的本地服务器上运行它(并纠正了错字),它输出为:

Array
(
    [0] => Array
        (
            [0] => a
            [1] => b
            [2] => c
        )

    [1] => Array
        (
            [0] => d
            [1] => e
        )

)

可能有一种更整洁的方式来做这件事(这有点程序化),但它应该可以完成这项工作。

【讨论】:

  • 我很久以前就有过这样的结果。我需要它看起来像pastebin.com/MYZWsevq。如果将每一行作为行放置,那么您会看到,在列中它们按字母顺序排列。 :)
  • array_chunk 将是一个很好的解决方案,但是当我尝试使用array( 'a', 'b', 'c', 'd', 'e' ) 时,我只能设置有多少行。我需要分布在另一个结构中。不是作为 ('a', 'b'), ('c', 'd'), ('e'),而是作为 ('a', 'c', 'e'), ('b', ' d')。我希望你明白我的意思。
  • Ahhh - 我想我现在明白了,你的数组是 array(r0c0, r1c0, r0c1, r1c1, r0c2) 其中 r 是行索引,c 是列索引,所以它有点垂直然后水平......
【解决方案5】:

怎么样:

$arrs = array(
    array('a','b','c'),
    array('a','b','c','d'),
    array('a','b','c','d','e'),
    array('a','b','c','d','e','f'),
    array('a','b','c','d','e','f','g')
);
$nbcols = 3;
foreach ($arrs as $arr) {
    $arr_size = count($arr);
    $nblines = ceil($arr_size/$nbcols);
    $res = array();
    $l = 0;
    foreach ($arr as $el) {
        if ($l == $arr_size - 1 && count($res[0]) < $nbcols) $l=0;
        $res[$l%$nblines][] = $el;
        $l++;
    }
    print_r($res);
}

输出:

Array
(
    [0] => Array
        (
            [0] => a
            [1] => b
            [2] => c
        )

)
Array
(
    [0] => Array
        (
            [0] => a
            [1] => c
            [2] => d
        )

    [1] => Array
        (
            [0] => b
        )

)
Array
(
    [0] => Array
        (
            [0] => a
            [1] => c
            [2] => e
        )

    [1] => Array
        (
            [0] => b
            [1] => d
        )

)
Array
(
    [0] => Array
        (
            [0] => a
            [1] => c
            [2] => e
        )

    [1] => Array
        (
            [0] => b
            [1] => d
            [2] => f
        )

)
Array
(
    [0] => Array
        (
            [0] => a
            [1] => d
            [2] => g
        )

    [1] => Array
        (
            [0] => b
            [1] => e
        )

    [2] => Array
        (
            [0] => c
            [1] => f
        )

)

【讨论】:

  • 不错的一个。与 a-g 的输出略有不同。如果没有来自@Eugene 的进一步回复,很难知道他希望如何将其格式化为超过 6 个项目。
【解决方案6】:

为了做到这一点,你需要做两个操作:

首先,将数组分成 3 组,尽可能均匀。

function array_grouped($arr, $group_count)
{
    if (!count($arr)) return array();
    $result = array();
    for ($i = $group_count; $i > 0; --$i)
    {
        # break off the next ceil(remaining count / remaining columns) elements
        # (avoiding FP math, cause that way lies madness)
        $result[] = array_splice($arr, 0, ((count($arr)-1) / $i) + 1);
    }
    return $result;
}

然后,“转置”数组,以便行和列交换位置。

function array_transposed($arr)
{
    $result = array();
    foreach ($arr as $x => $subarr)
    {
        foreach ($subarr as $y => $val)
        {
            if (!isset($result[$y])) $result[$y] = array();
            $result[$y][$x] = $val;
        }
    }
    return $result;
}

array_transposed(array_grouped($arr, 3)) 按您想要的顺序为您提供条目。

【讨论】:

    【解决方案7】:

    耶耶耶!!我懂了。如果你经常这样做,你可以把它变成一个函数。

    # Here we setup our array and the number of columns we want.
    $myArray = range('a','d');  
    $numCols = 3;
    
    # Here we break ourselves up into columns
    for ($i = 0; $i < $numCols; $i++) {
        $numRows = ceil(count($myArray) / ($numCols - $i));
        $columns[$i] = array_slice($myArray,0,$numRows);
        $myArray = array_slice($myArray,$numRows);
    }
    
    # Here we transpose our array to be in rows instead of columns.
    for ($i = 0; $i < $numCols; $i++) {
        for ($j = 0; $j < count($columns[$i]); $j++) {
            $rows[$j][$i] = $columns[$i][$j];
        }
    }
    
    # Our rows are now in $rows
    var_dump($rows);
    

    由此产生的输出是:

    array(2) {
      [0]=>
      array(3) {
        [0]=>
        string(1) "a"
        [1]=>
        string(1) "c"
        [2]=>
        string(1) "d"
      }
      [1]=>
      array(1) {
        [0]=>
        string(1) "b"
      }
    }
    

    【讨论】:

      【解决方案8】:

      如果简短地说,那么这里是该算法的一种方法。

      /**
       * @param array $toTransform
       * @param int $columnsMax
       * @return array
       */
      private function transformation( array $toTransform, $columnsMax = 3 )
      {
          // First divide array as you need
          $listlen   = count( $toTransform );
          $partlen   = floor( $listlen / $columnsMax );
          $partrem   = $listlen % $columnsMax;
          $partition = array();
          $mark      = 0;
      
          for ( $px = 0; $px < $columnsMax; $px++ )
          {
              $incr             = ( $px < $partrem ) ? $partlen + 1 : $partlen;
              $partition[ $px ] = array_slice( $toTransform, $mark, $incr );
              $mark             += $incr;
          }
      
          // Secondly fill empty slots for easy template use
          $result = array();
      
          for ( $i = 0; $i < count( $partition[0] ); $i++ )
          {
              $tmp = array();
      
              foreach ( $partition as $column )
              {
                  if ( isset( $column[ $i ] ) )
                  {
                      $tmp[] = $column[ $i ];
                  }
                  else
                  {
                      $tmp[] = '';
                  }
              }
      
              $result[] = $tmp;
          }
      
          return $result;
      }
      

      我还为此添加了 PHPUnit 测试。你可以在link找到它。

      【讨论】: