Отображение среза в списке со строкой и столбцом
У меня есть фрагмент с 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
2 ответа
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 цифры. Таким образом, мы можем использовать "заполнение", чтобы каждый элемент и индекс занимали один и тот же индекс. Это заполнение может быть просто пробелами, и столько, сколько нужно, чтобы все индексы занимали одно и то же место. Например, если мы предположим, что у нас менее 100 элементов, то мы можем использовать 1 пробел для чисел, меньших 10, и без пробелов для чисел 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.
Примечание № 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.
Заметка 2:
Также обратите внимание, что приведенный выше алгоритм может использовать меньше столбцов, чем то, что вы передаете. Это происходит в духе "минимизации" столбцов.
Например, если длина ввода равна 24, и вы передаете cols=10
это означает, что для представления 24 элементов требуется не менее 3 строк (2 строки могут отображать не более 20 элементов в 10 столбцах). Но если используются / используются 3 строки, то 24 элемента могут быть представлены всего в 8 столбцах, потому что 3*8 = 24.
Вот один из способов сделать это. Вы отобразили 6 строк в необходимом выводе, однако упомянули 6 рассматриваемых столбцов. Ссылка на игровую площадку
package main
import (
"fmt"
"strconv"
)
func main() {
fmt.Println("Hello, playground")
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 := range words {
words[i] = strconv.Itoa(i+1) + "." + words[i]
}
IterSplits(SliceSplit(words, 6), 6)
}
func IterSplits(slices[][] string, splitSize int){
for i := 0; i < splitSize; i ++ {
for _, s := range slices {
if len(s) > i {
fmt.Printf("%-15v", s[i])
}
}
println("")
}
}
func SliceSplit(aSlice[] string, splitSize int) [][]string{
var splits [][]string
for i := 0; i < len(aSlice); i += splitSize {
end := i + splitSize
if end > len(aSlice) {
end = len(aSlice)
}
splits = append(splits, aSlice[i:end])
}
return splits
}