首页 > 解决方案 > 切片显示在列表中的行和列

问题描述

我有 24 个单词的切片,我想以列表格式显示 4 行 6 列。我正在尝试在 Go 中实现它。

package main

import (
    "fmt"
)

func main() {
    words := []string{"peace", "note", "vapor", "notice", "meat", "shed", "immune", "law", "web", "security", "estate", "chat", "biology", "because", "visit", "inch", "credit", "void", "ability", "police", "crush", "begin", "matrix", "wreck"}
    for i, s := range words {
        fmt.Println(i, s)
    }
}

所需输出:

1.peace      7.immune         
2.note       8.law
3.vapor      9.web
4.notice     10.security
5.meat       11.estate
6.shed       12 chat

标签: stringgoslicegolang-migrate

解决方案


fmt包裹没有办法在终端中跳上一排。有控制字符,但它们通常依赖于终端,所以我们应该尽可能避免它们。

我们可以通过逐行打印元素来实现“表格”布局。如果我们有 4 行 6 列,这意味着第一行将包含 1. 元素,然后是 7. 元素,然后是 13. 等等。第二行将包含 2. 元素,然后是 8. 元素,然后14.元素等

一般来说,我们将有len(inputs) / cols行,四舍五入。这就是我们用整数算术表达的方式:

rows := (len(input) + cols - 1) / cols

并且一行中的元素将具有索引:

i := col*rows + row // col goes from 0 to cols

所以基本上我们可以使用for循环,遍历行,并打印行的元素。我们可以使用fmt.Printf()包含索引和元素的格式字符串,对所有元素使用相同的宽度(左对齐),如下所示:"%d.%-11s"(11 是元素的宽度,如果您有更长的输入文本,请调整它) .

然而,索引并不总是具有相同的宽度。例如,索引3有一个数字,而13有 2 个数字。所以我们可以使用一个“padding”来让每个元素和索引占据同一个索引。此填充可能只是空格,并且根据需要使所有索引占用相同的空间。例如,如果我们假设我们有少于 100 个元素,那么我们可以为小于 10 的数字使用 1 个空格,而对于数字 10..99 则没有空格。

事不宜迟,这是我们简单的table()打印函数,它足够通用,可以获取列数,并负责其余部分:

func table(input []string, cols int) {
    rows := (len(input) + cols - 1) / cols
    for row := 0; row < rows; row++ {
        for col := 0; col < cols; col++ {
            i := col*rows + row
            if i >= len(input) {
                break // This means the last column is not "full"
            }
            padding := ""
            if i < 9 {
                padding = " "
            }
            fmt.Printf("%d.%-11s%s", i+1, input[i], padding)
        }
        fmt.Println()
    }
}

让我们测试一下:

input := []string{
    "one", "two", "three", "four", "five", "six",
    "seven", "eight", "nine", "ten", "eleven", "twelve",
    "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen",
    "nineteen", "twenty", "twenty-one", "twenty-two", "twenty-three", "twenty-four",
}

table(input, 6)

对于上述内容,我们得到以下输出:

1.one         5.five        9.nine        13.thirteen   17.seventeen  21.twenty-one 
2.two         6.six         10.ten        14.fourteen   18.eighteen   22.twenty-two 
3.three       7.seven       11.eleven     15.fifteen    19.nineteen   23.twenty-three
4.four        8.eight       12.twelve     16.sixteen    20.twenty     24.twenty-four

现在让我们测试 5 列,其中最后一列不会“完整”:

table(input, 5)

这次输出将是:

1.one         6.six         11.eleven     16.sixteen    21.twenty-one 
2.two         7.seven       12.twelve     17.seventeen  22.twenty-two 
3.three       8.eight       13.thirteen   18.eighteen   23.twenty-three
4.four        9.nine        14.fourteen   19.nineteen   24.twenty-four
5.five        10.ten        15.fifteen    20.twenty     

在Go Playground上试试这些。

注意#1:

上述解决方案包含“连线”元素的“最大宽度”。如果你不能做出这样的假设,你可以先遍历元素以获得所有元素的最大宽度,并在格式字符串中使用它。

这是可以做到的:

maxWidth := 0
for _, s := range input {
    if len(s) > maxWidth {
        maxWidth = len(s)
    }
}
format := fmt.Sprintf("%%d.%%-%ds%%s", maxWidth)

然后format在打印元素时使用它:

fmt.Printf(format, i+1, input[i], padding)

在Go Playground上试试这个改进的版本。

笔记2:

另请注意,上述算法使用的列可能少于您传递的列。它本着“最小化”列的精神这样做。

例如,如果输入长度为 24 并且您通过cols=10,这意味着至少需要 3 行来呈现 24 个元素(2 行最多只能在 10 列中显示 20 个元素)。但是如果使用/利用了 3 行,那么 24 个元素可以在少至 8 列中呈现,因为 3*8 = 24。


推荐阅读