代码之家  ›  专栏  ›  技术社区  ›  Lance McNearney

将列表排序为多个垂直列

  •  6
  • Lance McNearney  · 技术社区  · 17 年前

    它工作的一个很好的例子是ASP.Net复选框列表控件呈现为一个方向设置为垂直的表。

    以下是输入和输出的示例:

    列=4

    输出:


    BDF

    谢谢

    我想我可能需要提供更多关于我正在尝试做什么的信息。。。这个问题主要来自于使用CheckBoxList的自动绑定(您可以指定要输出的列和方向,它将以正确的顺序输出项目表)到使用jQuery/AJAX创建复选框网格。因此,我尝试使用css和具有指定宽度的div块(在一个已知宽度的容器div中)复制该布局,以便它们在N个项目(或列)后换行。这也可以在表中呈现(如ASP.Net所做的)

    一切都很好,除了顺序是水平的,当列表中有大量项目时,更容易阅读垂直列。

    如果一个数组没有足够的项来生成一行,那么只需在一行中按原始顺序输出这些项即可。

    列=3
    数组={A”,“B”,“C”,“D”}

    ACD
    B


    亚齐
    BDF

    列=5

    ABCD

    3 回复  |  直到 17 年前
        1
  •  6
  •   Mecki    17 年前

    好的,我为我最初的陈述感到抱歉,但是当你想让它像你在我第一个答案的评论中所描述的那样工作时,你实际上需要对数据重新排序。。。嗯,有点。它可能不需要helper矩阵就可以完成,但是生成的代码可能非常复杂,只要矩阵只使用几个字节的内存,为什么不使用这个小helper构造呢?

    transposing a matrix ,按一个顺序写,但按另一个顺序读。转置矩阵是一个非常基本的数学运算(许多3D编程都是通过使用矩阵计算进行的,转置实际上是一个简单的运算)。诀窍在于我们最初如何填充矩阵。为了确保在任何情况下都可以填充第一列,与所需列的数量和数组的大小无关,如果元素用完,必须停止按正常顺序填充矩阵,并保留第一行剩余的所有元素。这将产生您在评论中建议的输出。

    老实说,整件事有点复杂,但背后的理论应该是理智的,而且工作起来很不错

    int Columns;
    char * Array[] = {"A", "B", "C", "D", "E", "F", "G"};
    
    int main (
        int argc,
        char ** argv
    ) {
        // Lets thest this with all Column sizes from 1 to 7
        for (Columns = 1; Columns <= 7; Columns++) {
    
            printf("Output when Columns is set to %d\n", Columns);
    
            // This is hacky C for quickly get the number of entries
            // in a static array, where size is known at compile time
            int arraySize = sizeof(Array) / sizeof(Array[0]);
    
            // How many rows we will have
            int rows = arraySize / Columns;
    
            // Below code is the same as (arraySize % Columns != 0), but
            // it's almost always faster
            if (Columns * rows != arraySize) {
                // We might have lost one row by implicit rounding
                // performed for integer division
                rows++;
            }
    
            // Now we create a matrix large enough for rows * Columns
            // references. Note that this array could be larger than arraySize!
            char ** matrix = malloc(sizeof(char *) * rows * Columns);
    
            // Something you only need in C, C# and Java do this automatically:
            // Set all elements in the matrix to NULL(null) references
            memset(matrix, 0, sizeof(char *) * rows * Columns );
    
            // We fill up the matrix from top to bottom and then from
            // left to right; the order how we fill it up is very important
            int matrixX;
            int matrixY;
            int index = 0;
            for (matrixX = 0; matrixX < Columns; matrixX++) {
                for (matrixY = 0; matrixY < rows; matrixY++) {
                    // In case we just have enough elements left to only
                    // fill up the first row of the matrix and we are not
                    // in this first row, do nothing.
                    if (arraySize + matrixX + 1 - (index + Columns) == 0 &&
                            matrixY != 0) {
                        continue;
                    }
    
                    // We just copy the next element normally
                    matrix[matrixY + matrixX * rows] = Array[index];
                    index++;
                    //arraySize--;
                }
            }
    
            // Print the matrix exactly like you'd expect a matrix to be
            // printed to screen, that is from left to right and top to bottom;
            // Note: That is not the order how we have written it,
            // watch the order of the for-loops!
            for (matrixY = 0; matrixY < rows; matrixY++) {
                for (matrixX = 0; matrixX < Columns; matrixX++) {
                    // Skip over unset references
                    if (matrix[matrixY + matrixX * rows] == NULL)
                        continue;
    
                    printf("%s", matrix[matrixY + matrixX * rows]);
                }
                // Next row in output
                printf("\n");
            }
            printf("\n");
    
            // Free up unused memory
            free(matrix);
        }   
        return 0;
    }
    

    输出为

    Output when Columns is set to 1
    A
    B
    C
    D
    E
    F
    G
    
    Output when Columns is set to 2
    AE
    BF
    CG
    D
    
    Output when Columns is set to 3
    ADG
    BE
    CF
    
    Output when Columns is set to 4
    ACEG
    BDF
    
    Output when Columns is set to 5
    ACEFG
    BD
    
    Output when Columns is set to 6
    ACDEFG
    B
    
    Output when Columns is set to 7
    ABCDEFG
    

    这段C代码应该很容易移植到PHP、C#、Java等,没有太大的魔力,所以它非常通用、可移植和跨平台。


    我要补充一件重要的事情:

    如果您将列设置为零(除以零,我不检查这一点),这段代码将崩溃,但是0列有什么意义呢?如果数组中的列多于元素,它也会崩溃,我也不检查这一点。您可以在获得阵列大小后立即轻松检查:

    if (Columns <= 0) {
       // Having no column make no sense, we need at least one!
       Columns = 1;
    } else if (Columns > arraySize) {
       // We can't have more columns than elements in the array!
       Columns = arraySize;
    }
    

    此外,您还应该检查arraySize是否为0,在这种情况下,您可以直接跳出函数,因为在这种情况下,函数完全无需执行任何操作:)添加这些检查将使代码坚如磐石。

    顺便说一句,在数组中使用NULL元素将有效,在这种情况下,结果输出中没有漏洞。空元素就像不存在一样被跳过。例如,让我们使用

    char * Array[] = {"A", "B", "C", "D", "E", NULL, "F", "G", "H", "I"};
    

    输出将是

    ADFI
    BEG
    CH
    

    对于列==4。如果你 ,则需要创建孔元素。

    char hole = 0;
    char * Array[] = {"A", "B", &hole, "C", "D", "E", &hole, "F", "G", "H", "I"};
    

    并稍微修改一下绘画代码

        for (matrixY = 0; matrixY < rows; matrixY++) {
            for (matrixX = 0; matrixX < Columns; matrixX++) {
                // Skip over unset references
                if (matrix[matrixY + matrixX * rows] == NULL)
                    continue;
    
                if (matrix[matrixY + matrixX * rows] == &hole) {
                    printf(" ");
                } else {
                    printf("%s", matrix[matrixY + matrixX * rows]);
                }
            }
            // Next row in output
            printf("\n");
        }
        printf("\n");
    

    输出样本:

    Output when Columns is set to 2
    A 
    BF
     G
    CH
    DI
    E
    
    Output when Columns is set to 3
    ADG
    BEH
      I
    CF
    
    Output when Columns is set to 4
    AC H
    BDFI
     EG
    
        2
  •  3
  •   Community Mohan Dere    6 年前

    一个小更新:

    我在这里使用的算法是一个修改过的,你可以用来画图像。我假设数组条目是图像的像素数据,然后从左到右(1.LtoR)和从上到下(2.TtoB)绘制图像,但是,图像数据是从上到下(1.TtoB)再从左到右(2.LtoR)存储的;按不同的顺序看。因为图像不能有 ,这就是它不能与5列或6列一起使用的原因。对于4列,输出为

    ACEG
    BDF
    

    作为图像,这看起来像这样

    OOOO
    OOO.
    

    OOO
    OO.
    OO.
    OO.
    

    如果您阅读,所有缺少的像素始终位于末尾 第一 然后

    如评论所示,有5列,应该是这样的

    ACEFG
    BD
    

    然而,正如图中所示,这看起来是这样的

    OOOOO
    OO...
    

    让我想一个解决方案,它将始终绘制所需的像素数(在单独的答复中)。


    您根本不需要重新排列内存中的数据。只需按所需顺序打印即可。

    int Columns = 4;
    char * Array[] = {"A", "B", "C", "D", "E", "F", "G"};
    
    int main (
        int argc,
        char ** argv
    ) {
        // This is hacky C for quickly get the number of entries
        // in a static array, where size is known at compile time
        int arraySize = sizeof(Array) / sizeof(Array[0]);
    
        // How many rows are we going to paint?
        int rowsToPaint = (arraySize / Columns) + 1;
    
        int col;
        int row;
        
        for (row = 0; row < rowsToPaint; row++) {
            for (col = 0; col < Columns; col++) {
                int index = col * rowsToPaint + row;
                
                if (index >= arraySize) {
                    // Out of bounds
                    continue;
                }
    
                printf("%s", Array[index]);
            }
            printf("\n"); // next row
        }
        printf("\n");
        return 0;
    }
    

    注意:如果值为8(因此所有内容都在一行内绘制),如果值为4及以下(对于3、2和1适用),则此选项可以正常工作,但对于5则无法正常工作。这不是算法的错误,而是约束的错误。

    ACEFG
    屋宇署
    

    该约束表示从上到下读取列以获得正确的排序数据。但在上面“ EFG

    ADG
    BE
    CF
    

    AE
    BF
    CG
    D
    

    一个人会把所有的东西都放在一列。

        3
  •  1
  •   Eric    17 年前

    这看起来像是家庭作业

    array<String^>^  sArray = {"A", "B", "C", "D", "E", "F", "G"};
    double Columns = 4;
    double dRowCount = Convert::ToDouble(sArray->Length) / Columns;
    int rowCount = (int) Math::Ceiling(dRowCount);
    int i = 0;
    int shift = 0;
    int printed = 0;
    while (printed < sArray->Length){
        while (i < sArray->Length){
            if (i % rowCount == shift){
                Console::Write(sArray[i]);
                printed++;
            }
            i++;
        }
        Console::Write("\n");
        i = 0;
        shift++;
    }
    
    推荐文章