I have a matrix of integers, represented by a multivariate array. I'm trying to concatenate the numbers into a string representation, rows-by-columns. My naive approach is to walk over all entries in the matrix and append them to a nullstring.
However, I'm getting an error that my append function is saying:
./main.go:xx:yy: first argument to append must be slice; have string
My code is:
type MatString string
type IntMat [3][3]Int // external constraints require fixed size, symmetric.
func Matrix2String(t IntMat) MatString {
// s var string
s := ""
for i := range t {
for j := range t[i] {
s = append(s[:], fmt.Sprintf("%s", j))
// fmt.Sprintf(s)
}
}
return MatString(s)
}
What am I misunderstanding about arrays, slices, and joins, and how can I iteratively build up this string correctly?
Collect the elements in a slice of strings. Join the slice to produce the result.
func Matrix2String(t IntMat) MatString {
var s []string
for i := range t {
for _, n := range t[i] {
s = append(s, fmt.Sprintf("%d", n))
}
}
return MatString(strings.Join(s, ""))
}
Another approach is to build the string in a []byte and convert at the end:
func Matrix2String(t IntMat) MatString {
var s []byte
for i := range t {
for _, n := range t[i] {
s = strconv.AppendInt(s, int64(n), 10)
}
}
return MatString(s)
}
I didn't include any delimiters because the question didn't include them.
You can simply concatenate converted integers to strings, to the response
func Matrix2String(t IntMat) MatString {
s := ""
for i := range t {
for _, n := range t[i] {
s += fmt.Sprintf("%d", n)
}
}
return MatString(s)
}
Playground
Related
I have an array of array of strings.
I want to repeat the "x" x times.
I do not want it to be in one string, like what happens using strings.Repeat(). I need it to be individual array items. Is that possible?
[]string{"x", "x", "x"}
You could do:
count := 10
strings.Split(strings.Repeat("x", count), "")
https://play.golang.org/p/zi0RqNT9lm9
or simply
func sliceFilledWithString(size int, str string) []string {
data := make([]string, size)
for i := 0; i < size; i++ {
data[i] = str
}
return data
}
https://play.golang.org/p/TR99bdH8ewX
With generics you can write a more general function. (Maybe something like this will be added to std lib.)
func sliceRepeat[T any](size int, v T) []T {
retval := make([]T, 0, size)
for i := 0; i < size; i++ {
retval = append(retval, v)
}
return retval
}
https://go2goplay.golang.org/p/5TIJRFNQPUY
In the function takeinput if i remove the 3 i get an error. My question what to do if i want to use this function to take in input for a different array whose column length is different.
package main
import ("fmt")
func takeinput(in [][3]int){
for i:=0;i<3;i++{
for j:=0;j<3;j++ {
fmt.Scanf("%d",&in[i][j])
}
}
}
func main(){
var a[3][3]int
fmt.Println("Enter the value for matrix one")
takeinput(a[:])
for i:=0;i<3;i++{
for j:=0;j<3;j++{
fmt.Printf("%d\t",a[i][j])
}
fmt.Println()
}
fmt.Println()
}
The error i get if i remove the 3 in input function.
# command-line-arguments
./matrix.go:19:13: cannot use a[:] (type [][3]int) as type [][]int in argument to takeinput
Use slice of slice instead, try this:
package main
import (
"fmt"
)
func takeinput(a [][]int) {
for i := range a {
for j := range a[i] {
fmt.Scanf("%d", &a[i][j])
}
}
}
func main() {
a := make([][]int, 3)
for i := range a {
a[i] = make([]int, 3)
}
fmt.Println("Enter the value for matrix one")
takeinput(a)
for i := range a {
for j := range a[i] {
fmt.Printf("%d\t", a[i][j])
}
fmt.Println()
}
fmt.Println()
}
Actually I am able to get it done using two loops in Go Language, for example if I have array as:
["aa", "aab", "bcd", "a", "cdf", "bb"]
I need to return strings with maxLength. So output will be:
["aab", "bcd", "cdf"]
Here's what I am doing.
package main
import "fmt"
func allLongestStrings(inputArray []string) []string {
maxLength := len(inputArray[0])
outputArray := []string{}
for _, value := range inputArray {
if len(value) > maxLength {
maxLength = len(value)
}
}
for _, val := range inputArray {
if len(val) == maxLength {
outputArray = append(outputArray, val)
}
}
return outputArray
}
func main() {
xs := []string{"aa", "aab", "bcd", "a", "cdf", "bb"}
fmt.Println(allLongestStrings(xs))
}
Is it possible to do this in one loop because I am running the same loop twice to find length and to append strings in outputArray.
Thanks In Advance.
Try this:
func allLongestStrings(inputArray []string) []string {
max := -1 // -1 is guaranteed to be less than length of string
var result []string
for _, s := range inputArray {
if len(s) < max {
// Skip shorter string
continue
}
if len(s) > max {
// Found longer string. Update max and reset result.
max = len(s)
result = result[:0]
}
// Add to result
result = append(result, s)
}
return result
}
As peterSO points out in another answer, the result slice can have a capacity larger than required and can contain string values past the length of slice. The extra allocation and string references may be a problem in some contexts (result is retained for a long time, strings are large, ...). Return a copy of the slice if the allocation and references are a concern.
func allLongestStrings(inputArray []string) []string {
...
return append([]string(nil), result...)
}
If the function can mutate the original slice, then the function result can be constructed in the input slice. This avoids the allocation of the result slice.
func allLongestStrings(inputArray []string) []string {
n := 0
max := -1
for i, s := range inputArray {
if len(s) < max {
// Skip shorter string
continue
}
if len(s) > max {
// Found longer string. Update max and reset result.
max = len(s)
n = 0
}
inputArray[n], inputArray[i] = inputArray[i], inputArray[n]
n++
}
return inputArray[:n]
}
I would do it by using the sort package. Basically, what you do is to create a custom sort function by implementing sort.Interface and use sort.Sort to your advantage.
package main
import "sort"
import "fmt"
type sortByLength []string
// Len implements Len of sort.Interface
func (s sortByLength) Len() int {
return len(s)
}
// Swap implements Swap of sort.Interface
func (s sortByLength) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
// Less implements Less of sort.Interface
func (s sortByLength) Less(i, j int) bool {
return len(s[i]) > len(s[j])
}
func main() {
toFind := []string{"aa", "aab", "bcd", "a", "cdf", "bb"}
// We sort it by length, descending
sort.Sort(sortByLength(toFind))
// The first element is sure to be the longest
longest := []string{toFind[0]}
// In case we have more than one element in toFind...
if len(toFind) > 1 {
// ...we need to find all remaining elements of toFind...
for _, str := range toFind[1:] {
// ...which are not smaller than the first element of longest.
if len(str) < len(longest[0]) {
// In case the current element is smaller in length, we can stop iterating
// over toFind.
break
}
// We know that str has the same length as longest[0], so we append it
longest = append(longest, str)
}
}
fmt.Println(longest)
}
Run it on Playground
However, while only having one loop in your own code, the sorting obviously iterates over the input, too.
For example, a more efficient version of #ThunderCat's solution,
package main
import "fmt"
func longest(a []string) []string {
var l []string
if len(a) > 0 {
l = append(l, a[0])
a = a[1:]
}
for _, s := range a {
if len(l[0]) <= len(s) {
if len(l[0]) < len(s) {
l = l[:0]
}
l = append(l, s)
}
}
return append([]string(nil), l...)
}
func main() {
a := []string{"aa", "aab", "bcd", "a", "cdf", "bb"}
fmt.Println(len(a), a)
l := longest(a)
fmt.Println(len(l), cap(l), l)
}
Playground: https://play.golang.org/p/JTvl4wVvSEK
Output:
6 [aa aab bcd a cdf bb]
3 4 [aab bcd cdf]
Reading #ThunderCat's solution, there is room for improvement. For example, for maximum and minimum problems, avoid using special values as an initial maximum or minimimun value. Don't overallocate memory and don't leave dangling pointers.
A Go string is implemented as:
type stringStruct struct {
str unsafe.Pointer
len int
}
If the list consists of 1,000 strings of length 1,000 followed by one string of length 1,001, the returned list will have a length of one and a capacity of at least 1,000. 999 entries have dangling pointers to 1,000 byte strings which the Go gc will be unable to release, wasting over one megabyte.
package main
import (
"fmt"
"strings"
"unsafe"
)
type stringStruct struct {
str unsafe.Pointer
len int
}
func main() {
var l []string
for n := 0; n < 1000; n++ {
l = append(l, strings.Repeat("x", 1000))
}
l = l[:0]
l = append(l, strings.Repeat("y", 1001))
over := (cap(l) - len(l)) * int(unsafe.Sizeof(stringStruct{}))
for i, o := len(l), l[:cap(l)]; i < cap(l); i++ {
over += len(o[i])
}
fmt.Println(over) // 1015368 bytes 64-bit, 1007184 bytes 32-bit
}
Playground: https://play.golang.org/p/Fi7EgbvdVkp
For a program to be correct, it must be readable. First, write the fundamental algorithms without the distraction of errors or special cases.
var l []string
for _, s := range a {
if len(l[0]) <= len(s) {
if len(l[0]) < len(s) {
l = l[:0]
}
l = append(l, s)
}
}
Next, add special cases, without disrupting the flow of the fundamental algorithm. In this case, handle zero- and one-length lists.
var l []string
if len(a) > 0 {
l = append(l, a[0])
a = a[1:]
}
for _, s := range a {
if len(l[0]) <= len(s) {
if len(l[0]) < len(s) {
l = l[:0]
}
l = append(l, s)
}
}
Finally, ensure that the function is efficient for both CPU and memory. The allocation is precise and there are no dangling pointers to unused strings.
var l []string
if len(a) > 0 {
l = append(l, a[0])
a = a[1:]
}
for _, s := range a {
if len(l[0]) <= len(s) {
if len(l[0]) < len(s) {
l = l[:0]
}
l = append(l, s)
}
}
return append([]string(nil), l...)
I have been giving HackerRank a try where the problems often require reading lines of integers into arrays (slices).
For many of the problems, my parsing code ends up being larger than the algorithmic meat of the solution. For instance, that was the case in Sherlock and Array
Any ideas on how to concisely parse a space-separated line of integers into a slice? fmt.Scanf doesn't support slices and when using bufio I get long solutions.
Some requirements:
You can only use the standard library.
The solution should be concise, the shorter the better.
Error checks shouldn't be skipped. I know that the input is well defined in HackerRank and you should be able to cut corners, but please don't, it's bad practice.
It should be reasonably efficient.
NOTE:
The parser should only consume a single line and not the full input.
Well, I have done some hackerrank problems too, and here is what I came up with. Typically, problems start with the number of items in the array:
func main() {
var N int
fmt.Scanf("%d", &N)
line := make([]int, N)
for i, _ := range line {
fmt.Scanf("%d", &line[i])
}
// Do something with the values
}
// inputs space separated list of integers, outputs []int64
package main
import (
"bufio"
"fmt"
"strconv"
"strings"
)
func main() {
fmt.Println(parse("100 200 300"))
}
func parse(i string) (o []int64) {
// from https://golang.org/pkg/bufio/#example_Scanner_custom
s := bufio.NewScanner(strings.NewReader(i))
splitter := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
advance, token, err = bufio.ScanWords(data, atEOF)
if err == nil && token != nil {
x, err := strconv.ParseInt(string(token), 10, 32)
if err != nil {
panic(err)
}
o = append(o, x)
}
return
}
s.Split(splitter)
for s.Scan() {
}
return o
}
You can use fmt.Scanf, but you need to keep track of the values you're getting.
// a.go
package main
import (
"fmt"
"io"
)
func main() {
var (
next int
nums []int
)
for {
n, err := fmt.Scanf("%d", &next)
if err == io.EOF {
break
}
if err != nil {
panic(err)
}
if n == 0 {
break
}
nums = append(nums, next)
}
fmt.Printf("%#v\n", nums)
}
$ echo "4 8 15 16 23 42" | go run a.go
[]int{4, 8, 15, 16, 23, 42}
1) read string
2) prepend [ and append ]
3) parse as json into []int?
var input = "1,2,3"
var answer []int
j := []byte(fmt.Sprintf("[%s]",input))
err:= json.Unmarshal(j, &input)
if err != nil {
panic(err)
}
for k,v := range input {
fmt.Printf("Element №%v is %v\n", k,v)
}
also using split strings (https://godoc.org/strings#Split)
and https://godoc.org/strconv#ParseInt
input:= "1,2,3"
temp := strings.Split(input, ",")
var answer []int
for _,v := range temp {
i,err := strconv.ParseInt(v)
if err != nill {
panic(err)
}
answer = append(answer, i)
}
UPD: just found that the numbers are SPACE separated.
So, this code have to do the thing:
input:= "1 2 3"
temp := strings.Split(input, " ")
var answer []int
for _,v := range temp {
i,err := strconv.ParseInt(v)
if err != nill {
panic(err)
}
answer = append(answer, i)
}
func main() {
arr := make([]int, 0)
reader := bufio.NewReaderSize(os.Stdin, 1024*1024)
for {
line, _, err := reader.ReadLine()
if err != nil {
if err == io.EOF {
break
}
panic(err)
}
str := strings.Split(string(line), " ")
for i:=0; i<len(str); i++ {
v, _ := strconv.Atoi(str[i])
arr = append(arr, v)
}
}
fmt.Println(arr)
}
I've used this for those times playing in hackerrank (so concise, but not tested for humans):
func scanInt(n int) []int {
input := make([]int, n)
buffer := make([]interface{}, n)
for i := 0; i < n; i++ {
buffer[i] = &input[i]
}
fmt.Scanln(buffer...)
return input
}
When I run the code below I get the error:
school_mark.go:8: invalid array bound s
My code:
package main
import "fmt"
func main(){
var subj float64
fmt.Println("Enter how much you have subjects inn school: ")
fmt.Scanf("%f", &subj)
s := subj
var mark [s]float64
var a float64
for a = 0; a<s; a++{
fmt.Scanf("%f", &mark)
}
var total float64
var i float64
for i= 0; i<subj; i++{
total += mark[i]
}
fmt.Println(total/subj)
}
What is the problem?
Spec: Array types:
The length is part of the array's type; it must evaluate to a non-negative constant representable by a value of type int.
Your length in [s]float64 is not a constant.
Use a slice instead of an array type, and know that you have to use integer type for the length, e.g.:
var mark []float64 = make([]float64, int(s))
Or short:
mark := make([]float64, int(s))
Going forward, always use integer types (e.g. int) for indices. You can declare it in for like:
for i := 0; i < len(mark); i++ {
fmt.Scanf("%f", &mark[i])
}
Or you can even use for ... range to range over the indices of the slice:
for i := range mark {
fmt.Scanf("%f", &mark[i])
}
I would also use int type everywhere: the number of subjects and marks themselves do not have a meaning if they are non integers.
Also fmt.Scanf() does not consume newline, subsequent fmt.Scanf() call will return immediately with an error.
You should also check errors or successfully parsed values, both which are returned by the fmt.Scan*() functions.
Also you don't have to loop the slice twice, you can calculate total (the sum) in the first.
Going even more forward, you don't even have to store the marks in the slice, you could just ask the entered number of marks, calculate sum on the fly and print the average.
Something like this:
var n, total, mark int
fmt.Println("Number of subjects:")
fmt.Scanln(&n)
for i := 0; i < n; i++ {
fmt.Scanln(&mark)
total += mark
}
fmt.Println("Average:", float64(total)/float64(n))
If you were to add all the required checks, it could look like this:
var n, total, mark int
fmt.Print("Number of subjects: ")
if _, err := fmt.Scanln(&n); err != nil || n <= 0 {
fmt.Println("Wrong number!")
return
}
for i := 0; i < n; i++ {
fmt.Printf("Enter %d. mark: ", i+1)
if _, err := fmt.Scanln(&mark); err != nil || mark < 1 || mark > 5 {
fmt.Println("Wrong mark, enter it again!")
fmt.Scanln()
i-- // We're gonna re-scan the same mark
} else {
total += mark
}
}
fmt.Println("Average:", float64(total)/float64(n))