1

I have slice with 24 words, I want to display it with 4 row with 6 column in list format. I am trying to implement it in 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)
    }
}

Required output:

1.peace      7.immune         
2.note       8.law
3.vapor      9.web
4.notice     10.security
5.meat       11.estate
6.shed       12 chat
icza
  • 389,944
  • 63
  • 907
  • 827
Nagaraj M
  • 387
  • 1
  • 5
  • 16

2 Answers2

3

Here is one way to do it. You have displayed 6 rows in required output however mentioned 6 columns in question. Link to playground

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
}
Abhijit-K
  • 3,569
  • 1
  • 23
  • 31
3

The fmt package does not have means to jump up one row in the terminal. There are control characters, but they are usually terminal-dependant, so we should avoid them if we can.

We can achieve the "table" layout by printing the elements by rows. If we have 4 rows and 6 columns, that means the first row will contain the 1. element, then the 7. element, then the 13. etc. The second row will contain the 2. element, then the 8. element, then the 14. element etc.

In general, we will have len(inputs) / cols rows, rounded up. This is how we can express that with integer arithmetic:

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

And the elements in a row will have indices:

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

So basically we may use a for loop, iterating over the rows, and print the elements of the row. We may use fmt.Printf() with a format string that contains the index and the element, using the same width for all elements (left aligned), something like this: "%d.%-11s" (the 11 is the width for the elements, adjust that if you have longer input texts).

The index however does not always have the same width. E.g. the index 3 has a single digit, while 13 has 2 digits. So we may use a "padding" to make each element and index occupy the same index. This padding may simply be spaces, and as many as needed to make all indices occupy the same space. E.g. if we assume we have less than 100 elements, then we may use 1 space for numbers less than 10, and no spaces for numbers 10..99.

Without further ado, here's our simple table() printing function, that's generic enough to take the number of columns, and takes care of the rest:

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()
    }
}

Let's test it:

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)

For the above, we get this output:

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

Now let's test with 5 columns where the last column will not be "complete":

table(input, 5)

This time output will be:

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     

Try these on the Go Playground.

Note #1:

The above solution contains the "max width" of elements "wired in". If you can't make such assumption, you may iterate over the elements first to get the max width of all elements, and use that in the format string.

This is how it can be done:

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

Then this format is to be used when printing elements:

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

Try this improved version on the Go Playground.

Note #2:

Also note that the above algorithm might use less columns than what you pass. It does so in the spirit of "minimizing" columns.

For example if input length is 24 and you pass cols=10, that means at least 3 rows is required to present the 24 elements (2 rows could only display 20 elements at most in 10 columns). But if 3 rows are used / utilized, then 24 elements can be presented in as few as 8 columns, because 3*8 = 24.

icza
  • 389,944
  • 63
  • 907
  • 827
  • @NagarajM Simplified and fixed a bug in the original code, also added a 2nd note. See edited answer. – icza Jul 10 '19 at 17:05