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))
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
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 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
I am trying to generate numbers that are factors of 3 || 5 in an array.
Here is a copy of my code:
package main
import "fmt"
func main() {
i := 0
for i < 1000 {
var nums []int
if i%3 == 0 || i%5 == 0 {
nums := append(nums, i)
fmt.Println(nums)
}
i++
}
}
Unfortunately, this isnt going as planned as it appears to by over writing the value at nums[0]. Here a the last few values of my terminal output.
[981]
[984]
[985]
[987]
[990]
[993]
[995]
[996]
[999]
What am I doing wrong?
UPDATE
Also tried this:
var nums []int // initialize the slice outside for loop
for i < 1000 {
if i%3 == 0 || i%5 == 0 {
nums = append(nums, i) // append to the slice outside loop not create a new one using short variable declaration
fmt.Println(nums)
}
i++
}
But got Same result
This is because you are creating a new variable of []int slice rather than appending to the created one outside if condition. Create the []int slice outside for loop and don't create a new variable using short declaration inside if condition.
package main
import (
"fmt"
)
func main() {
i := 0
var nums []int
for i < 1000 {
if i%3 == 0 || i%5 == 0 {
nums = append(nums, i)
}
i++
}
fmt.Println(nums)
fmt.Println(len(nums), cap(nums)) // check for length and capacity of slice to know the size of slice after appending all data
}
Working Code on Go playground
Problem
I have array of structs:
type Config struct {
Applications []Application
}
Note: Config - is a struct for json.Decode.
config = new(Config)
_ = decoder.Decode(&config)
In loop I have some condition and element deletion by key.
for i, application := range config.Applications {
if i == 1 {
config.Applications = _removeApplication(i, config.Applications)
}
}
func _removeApplication(i int, list []Application) []Application {
if i < len(list)-1 {
list = append(list[:i], list[i+1:]...)
} else {
log.Print(list[i].Name)
list = list[:i]
}
return list
}
But always I have "out of range" error. What is the best way to delete element by key from array of structs?
Quoting from the Slice Tricks page deleting the element at index i:
a = append(a[:i], a[i+1:]...)
// or
a = a[:i+copy(a[i:], a[i+1:])]
Note that if you plan to delete elements from the slice you're currently looping over, that may cause problems. And it does if the element you remove is the current one (or a previous element already looped over) because after the deletion all subsequent elements are shifted, but the range loop does not know about this and will still increment the index and you skip one element.
You can avoid this by using a downward loop:
for i := len(config.Applications) - 1; i >= 0; i-- {
application := config.Applications[i]
// Condition to decide if current element has to be deleted:
if haveToDelete {
config.Applications = append(config.Applications[:i],
config.Applications[i+1:]...)
}
}
You are getting this error because you are doing a loop over a slice with an inital range of X length that became X-n because you remove some elements during loop.
If you want to delete an item at a specific index from a slice, you can do it this way:
sliceA = append(sliceA[:indexOfElementToRemove], sliceA[indexOfElementToRemove+1:]...)
This question is a bit older but I haven't found another answer on StackOverflow which mentions the following trick from the Slice Tricks to filter a list:
b := a[:0]
for _, x := range a {
if f(x) {
b = append(b, x)
}
}
So in this case a function which deletes certain elements could look like this:
func removeApplications(apps []Applications) []Applications {
filteredApps := apps[:0]
for _, app := apps {
if !removeApp {
filteredApps = append(filteredApps, app)
}
}
return filteredApps
}
I think the simple way is
var (
slice = []int{1,2,3,4,5}
pos int
)
for _, i := range slice {
if i == 3 {
slice = append(slice[:pos], slice[pos+1:]...)
if pos > 0 {
pos = pos - 1
}
continue
}
pos++
}
here is...
https://play.golang.org/p/pK3B5Mii9k
To remove a particular slice from a struct we need to run a for-loop to find that particular slice and delete it
for example:
type variable struct {
Id int `json:"id"`
Message string `json:"message"`
}
var mssg = []variable{
{Id: 1, Message: "success"},
{Id: 2, Message: "failed"}
}
for i, a := range mssg {
if a.Message == "success" {
mssg = append(mssg[:i], mssg[i+1:]...)
fmt.Println(mssg)
}