golang append to 2d slice - amazon-web-services

I'm trying to create slice of slices.
In all the examples the inner slices are integer based.
I'm trying to create a slice of string slices.
Example:
[
[Name1,State1,Tags.Owner1]
[Name2,State2,Tags.Owner2]
[Name3,State3,Tags.Owner3]
]
I'm trying to do it this way:
outerList := [][]string{}
i := 0
for _,c := range clusters {
input := &eks.DescribeClusterInput{
Name: aws.String(c),
}
resp,err := svc.DescribeCluster(input)
if err != nil {
errorOut(`clusterData function: `+err.Error())
}
record := resp.Cluster
data,_ := json.Marshal(record)
error := json.Unmarshal(data, &cluster)
if error != nil {errorOut(error.Error())}
innerList := [...]string{cluster.Name,cluster.Tags["Vsad"],cluster.Status}
outerList[string(i)] = innerList
}
I get the below error:
non-integer slice index string(i)
cannot use innerList (type [3]string) as type []string in assignment
I know in Python I can simply do:
outerList = list()
for c in cluster:
a = [c.Name,c.State,c.Tags.Owner]
outerList.append(a)

You can use append. Formatted as follows:
// make room for clusters
outerList := make([][]string, len(clusters))
// iterate and fill cluster data
for i, c := range clusters {
// some processing where cluster variable is setupped
// add new inner slice
outerList[i] = append(outerList[i], cluster.Name, cluster.Tags["Vsad"], cluster.Status)
}

Related

(SOLVED) Exception from HRESULT: 0x800A01A8 Dynamic Navision 2016

I wrote a code where user filters a source number from the table, the code get the source number and open an Excel file with the same number in a folder, write other data into the file and then save to temp folder. The program worked for some of the Excel files in the folder, but it won't work for the majority of the files. When it finishes running it'll say Exception from HRESULT: 0x800A01A8, the file gets saved into temp folder but the data is not written into it.
https://i.stack.imgur.com/kHtbC.png
I have searched all over Google but it seems like no one had encountered the same issue as I am and I have no idea what this exception means. Below is the code.
ProductionOrder - OnAfterGetRecord()
CLEAR(xlApplication);
CLEAR(xlWorkbooks);
CLEAR(xlWorksheet);
CLEAR(xlshape);
// Open excel
IF CREATE(xlApplication, FALSE, TRUE) THEN BEGIN
xlApplication.SheetsInNewWorkbook := 1;
xlApplication.ScreenUpdating(TRUE);
xlWorkbooks := xlApplication.Workbooks;
END ELSE ERROR('Could not start Excel.');
xlWorkbooks.Open('C:\PROCESS CHECKSHEET\' + ProductionOrder."Source No." + '.xlsx');
xlWorkbook := xlApplication.ActiveWorkbook;
xlSheets := xlWorkbook.Worksheets;
FOR i := 1 TO xlSheets.Count DO BEGIN
xlWorksheet := xlSheets.Item(i);
xlWorksheet.Activate;
xlRange := xlWorksheet.Range(xlsCell(14,7));
xlRange.Value := ProductionOrder."No.";
xlRange := xlWorksheet.Range(xlsCell(14,8));
xlRange.Value := FORMAT(ProductionOrder.Quantity);
xlWorkbook._SaveAs('C:\temp\' + ProductionOrder."Source No.");
xlWorkbook.Close(TRUE);
xlApplication.Quit;
END;
CurrReport.QUIT;
LOCAL xlsCol(col : Integer) : Text
IF col > 26 THEN BEGIN
ColFirst := col DIV 26;
col := col MOD 26;
END
ELSE
ColFirst := 0;
Letters := 'ABCDEFGHIJKLMNOPQRSTUVYWXYZ';
IF ColFirst <> 0 THEN
EXIT (STRSUBSTNO('%1%2',Letters[ColFirst],Letters[col]))
ELSE
EXIT (STRSUBSTNO('%1',Letters[col]));
LOCAL xlsCell(col : Integer;row : Integer) : Text[15]
EXIT (STRSUBSTNO('%1%2',xlsCol(col),row));
Edit:
I have tried to debug. Debugger says error is on line "xlWorksheet := xlSheets.Item(i);". There is only one sheet in the Excel file that I am trying to access. What I don't understand is that it would work on other Excel files, just not on this file that I am currently trying to access.
I also found out that if I copy the content into a new Excel file, then the code would work on the new Excel file. Could it also be a problem of Excel version?
I solved this on my own.
Because the Excel files were given to me by my HOD at work (and these Excel files were written by other department), I did not know that there was a hidden sheet inside those Excel files, hence it output the exception error because my code was only indexing Excel file that only has one sheet. I changed my index to 2 and it worked. Note to self, next time gotta check for hidden sheets.
I don't know if there is a for each sheet equivalent for C/AL programming because I'm new to the language, so I used 2 for loops to solve the problem.
CLEAR(xlApplication);
CLEAR(xlWorkbooks);
CLEAR(xlWorksheet);
IF CREATE(xlApplication, FALSE, TRUE) THEN BEGIN
xlApplication.SheetsInNewWorkbook := 1;
xlApplication.ScreenUpdating(TRUE);
xlWorkbooks := xlApplication.Workbooks;
END ELSE ERROR('Could not start Excel.');
xlWorkbooks.Open('C:\13. PROCESS CHECKSHEET\' + ProductionOrder."Source No." + '.xlsx');
xlWorkbook := xlApplication.ActiveWorkbook;
xlSheets := xlWorkbook.Worksheets;
FOR I := 1 TO xlSheets.Count DO BEGIN
xlWorksheet := xlSheets.Item(I);
xlWorksheet.Activate;
xlRange := xlWorksheet.Range(xlsCell(14,7));
xlRange.Value := ProductionOrder."No.";
xlRange := xlWorksheet.Range(xlsCell(14,8));
xlRange.Value := FORMAT(ProductionOrder.Quantity);
END;
FOR I := 2 TO xlSheets.Count DO BEGIN
xlWorksheet := xlSheets.Item(I);
xlWorksheet.Activate;
IF (FORMAT(xlWorksheet.Name) = 'PROCESS CHECKSHEET') OR (FORMAT(xlWorksheet.Name) = 'Process Checksheet') THEN BEGIN
xlRange := xlWorksheet.Range(xlsCell(14,7));
xlRange.Value := ProductionOrder."No.";
xlRange := xlWorksheet.Range(xlsCell(14,8));
xlRange.Value := FORMAT(ProductionOrder.Quantity);
END;
END;
xlWorkbook.SaveAs('C:\13. PROCESS CHECKSHEET\temp\' + ProductionOrder."Source No.");
MESSAGE('Success');
xlWorkbook.Close(TRUE);
xlApplication.Quit;
CurrReport.QUIT;

How to update field value in a Go template

I have the following case, where I am passing a struct containing a map to a template:
package main
import (
"log"
"os"
"text/template"
)
var fns = template.FuncMap{
"plus1": func(x int) int {
return x + 1
},
}
type codec struct {
Names map[string]string
Count int
}
func main() {
a := map[string]string{"one": "1",
"two": "2",
"three": "3"}
t := template.Must(template.New("abc").Funcs(fns).Parse(`{{$l := len .Names}}{{range $k, $v := .Names}}{{if ne (plus1 $.Count) $l}}{{$k}} {{$v}} {{end}}{{end}}.`))
err := t.Execute(os.Stdout, codec{a, 0})
if err != nil {
log.Println(err)
}
}
I would like to increment the Count field of codec so that I can know how many items of the map I've seen.
One solution is to make the plus1 function a closure that acts directly on the value of the codec:
// first create a codec instance
c := codec {a, 0}
// now define the function as a closure with a reference to c
fns := template.FuncMap{
"plus1": func() int {
c.Count++
return c.Count
},
}
// now we don't need to pass anything to it in the template
t := template.Must(template.New("abc").Funcs(fns).Parse(`{{$l := len .Names}}{{range $k, $v := .Names}}{{if ne (plus1) $l}}{{$k}} {{$v}} {{end}}{{end}}.`))
The output was:
one 1 three 3
which I'm guessing is what you were aiming for? And the value is retained in c at the end of execution.
You can simply define a method on your struct:
type codec struct {
Names map[string]string
Count int
}
func (c *codec) IncAndGet() int {
c.Count++
return c.Count
}
Calling it from a template:
c := &codec{Count: 2}
t := template.Must(template.New("").Parse(`{{.IncAndGet}} {{.IncAndGet}}`))
t.Execute(os.Stdout, c)
Output (try it on the Go Playground):
3 4
Note that for this to work, the method needs a pointer receiver (func (c *codec) IncAndGet()) and you have to pass a pointer to Template.Execute() (c is a pointer in our example: c := &codec{Count: 2}).
If you don't want any result just counting, define it to have a string return type and return the empty string "":
func (c *codec) Inc() string {
c.Count++
return ""
}

text/template: space in map's key

I have the following code (using text/template):
inventory := map[string]string{"name of the movie": "hello"}
tmpl, err := template.New("test").Parse("Movie name ") // I want to display "hello" there
if err != nil { panic(err) }
err = tmpl.Execute(os.Stdout, inventory)
if err != nil { panic(err) }
As you can see, there is spaces in my map's key name of the movie. How can I do in the parse argument to display hello (which is the value of name of the movie)?
Use the index function: Movie name: {{index . "name of the movie"}}
From the docs:
index
Returns the result of indexing its first argument by the
following arguments. Thus "index x 1 2 3" is, in Go syntax,
x[1][2][3]. Each indexed item must be a map, slice, or array.

Pascal - doubly linket list

I'm trying compile Doubly linked list but I have one small problem with this part of code :
It's a "insert after"
When I insert data to the list : 1 2 3 4 5 and want insert after number 4 for example number 9, number 9 is inserted like this : 1 9 2 3 4 5. I really dont know where I have wrong code:(
everytime i insert new number to second position..
procedure insertAfter(var L:Plist; n_p:integer);
var novy_za:Plist;
begin
new(novy_za);
novy_za^.info:=n_p;
novy_za^.next:=L^.next;
novy_za^.prev:=L;
L^.next:=novy_za;
if novy_za^.next<>nil
then novy_za^.next^.prev:=novy_za;
end;
procedure call :
begin
writeln;
write('which number insert : '); readln(x);
writeln;
write('insert after : '); readln(Y);
InsertAfter(P,x);
end;
Here's a corrected version of your routine. Your original failed to accept the value you want to insert after as an argument. I made it a function so that it returns the pointer to the new added element if it was able to find the one you wanted to insert after. Otherwise, it returns nil. You call it with a second argument which tells it what value you want to insert after.
function insertAfter(var L: Plist; n_a, n_p: integer): Plist;
var novy_za, cur_za: Plist;
begin
cur_za := L;
novy_za := nil;
{ Traverse the list, looking for value n_a and, if found, insert the new
element n_p after it }
while cur_za <> nil do begin
{ Insert the new element after the one with value n_a }
if cur_za^.info = n_a then begin
new(novy_za);
novy_za^.info := n_p;
novy_za^.next := cur_za^.next;
novy_za^.prev := cur_za;
cur_za^.next := novy_za;
if novy_za^.next <> nil then
novy_za^.next^.prev := novy_za;
break; { Exit the loop }
end;
cur_za := cur_za^.next;
end;
insertAfter := novy_za;
end;
Function call (this assumes P is defined somewhere as a valid Plist, and x and y are defined as info type):
begin
writeln;
write('which number insert : '); readln(x);
writeln;
write('insert after : '); readln(y);
{ Insert the value x after the number y }
if insertAfter(P, y, x) = nil then
writeln('The value ', y, ' was not found')
else
writeln('The value ', x, ' was successfully inserted after ', y);
end;

Does Go have "if x in" construct similar to Python?

How can I check if x is in an array without iterating over the entire array, using Go? Does the language have a construct for this?
Like in Python:
if "x" in array:
# do something
There is no built-in operator to do it in Go. You need to iterate over the array. You can write your own function to do it, like this:
func stringInSlice(a string, list []string) bool {
for _, b := range list {
if b == a {
return true
}
}
return false
}
Or in Go 1.18 or newer, you can use slices.Contains (from golang.org/x/exp/slices).
If you want to be able to check for membership without iterating over the whole list, you need to use a map instead of an array or slice, like this:
visitedURL := map[string]bool {
"http://www.google.com": true,
"https://paypal.com": true,
}
if visitedURL[thisSite] {
fmt.Println("Already been here.")
}
Another solution if the list contains static values.
eg: checking for a valid value from a list of valid values:
func IsValidCategory(category string) bool {
switch category {
case
"auto",
"news",
"sport",
"music":
return true
}
return false
}
This is quote from the book "Programming in Go: Creating Applications for the 21st Century":
Using a simple linear search like this is the only option for unsorted
data and is fine for small slices (up to hundreds of items). But for
larger slices—especially if we are performing searches repeatedly—the
linear search is very inefficient, on average requiring half the items
to be compared each time.
Go provides a sort.Search() method which uses the binary search
algorithm: This requires the comparison of only log2(n) items (where n
is the number of items) each time. To put this in perspective, a
linear search of 1000000 items requires 500000 comparisons on average,
with a worst case of 1000000 comparisons; a binary search needs at
most 20 comparisons, even in the worst case.
files := []string{"Test.conf", "util.go", "Makefile", "misc.go", "main.go"}
target := "Makefile"
sort.Strings(files)
i := sort.Search(len(files),
func(i int) bool { return files[i] >= target })
if i < len(files) && files[i] == target {
fmt.Printf("found \"%s\" at files[%d]\n", files[i], i)
}
https://play.golang.org/p/UIndYQ8FeW
Just had a similar question and decided to try out some of the suggestions in this thread.
I've benchmarked best and worst-case scenarios of 3 types of lookup:
using a map
using a list
using a switch statement
Here's the function code:
func belongsToMap(lookup string) bool {
list := map[string]bool{
"900898296857": true,
"900898302052": true,
"900898296492": true,
"900898296850": true,
"900898296703": true,
"900898296633": true,
"900898296613": true,
"900898296615": true,
"900898296620": true,
"900898296636": true,
}
if _, ok := list[lookup]; ok {
return true
} else {
return false
}
}
func belongsToList(lookup string) bool {
list := []string{
"900898296857",
"900898302052",
"900898296492",
"900898296850",
"900898296703",
"900898296633",
"900898296613",
"900898296615",
"900898296620",
"900898296636",
}
for _, val := range list {
if val == lookup {
return true
}
}
return false
}
func belongsToSwitch(lookup string) bool {
switch lookup {
case
"900898296857",
"900898302052",
"900898296492",
"900898296850",
"900898296703",
"900898296633",
"900898296613",
"900898296615",
"900898296620",
"900898296636":
return true
}
return false
}
Best-case scenarios pick the first item in lists, worst-case ones use nonexistent value.
Here are the results:
BenchmarkBelongsToMapWorstCase-4 2000000 787 ns/op
BenchmarkBelongsToSwitchWorstCase-4 2000000000 0.35 ns/op
BenchmarkBelongsToListWorstCase-4 100000000 14.7 ns/op
BenchmarkBelongsToMapBestCase-4 2000000 683 ns/op
BenchmarkBelongsToSwitchBestCase-4 100000000 10.6 ns/op
BenchmarkBelongsToListBestCase-4 100000000 10.4 ns/op
Switch wins all the way, worst case is surpassingly quicker than best case.
Maps are the worst and list is closer to switch.
So the moral is:
If you have a static, reasonably small list, switch statement is the way to go.
The above example using sort is close, but in the case of strings simply use SearchString:
files := []string{"Test.conf", "util.go", "Makefile", "misc.go", "main.go"}
target := "Makefile"
sort.Strings(files)
i := sort.SearchStrings(files, target)
if i < len(files) && files[i] == target {
fmt.Printf("found \"%s\" at files[%d]\n", files[i], i)
}
https://golang.org/pkg/sort/#SearchStrings
This is as close as I can get to the natural feel of Python's "in" operator. You have to define your own type. Then you can extend the functionality of that type by adding a method like "has" which behaves like you'd hope.
package main
import "fmt"
type StrSlice []string
func (list StrSlice) Has(a string) bool {
for _, b := range list {
if b == a {
return true
}
}
return false
}
func main() {
var testList = StrSlice{"The", "big", "dog", "has", "fleas"}
if testList.Has("dog") {
fmt.Println("Yay!")
}
}
I have a utility library where I define a few common things like this for several types of slices, like those containing integers or my own other structs.
Yes, it runs in linear time, but that's not the point. The point is to ask and learn what common language constructs Go has and doesn't have. It's a good exercise. Whether this answer is silly or useful is up to the reader.
Another option is using a map as a set. You use just the keys and having the value be something like a boolean that's always true. Then you can easily check if the map contains the key or not. This is useful if you need the behavior of a set, where if you add a value multiple times it's only in the set once.
Here's a simple example where I add random numbers as keys to a map. If the same number is generated more than once it doesn't matter, it will only appear in the final map once. Then I use a simple if check to see if a key is in the map or not.
package main
import (
"fmt"
"math/rand"
)
func main() {
var MAX int = 10
m := make(map[int]bool)
for i := 0; i <= MAX; i++ {
m[rand.Intn(MAX)] = true
}
for i := 0; i <= MAX; i++ {
if _, ok := m[i]; ok {
fmt.Printf("%v is in map\n", i)
} else {
fmt.Printf("%v is not in map\n", i)
}
}
}
Here it is on the go playground
In Go 1.18+, you can now declare generic Contains function which is also implemented in the experimental slice function. It works for any comparable type
func Contains[T comparable](arr []T, x T) bool {
for _, v := range arr {
if v == x {
return true
}
}
return false
}
and use it like this:
if Contains(arr, "x") {
// do something
}
// or
if slices.Contains(arr, "x") {
// do something
}
which I found here
try lo: https://github.com/samber/lo#contains
present := lo.Contains[int]([]int{0, 1, 2, 3, 4, 5}, 5)