Created
January 7, 2021 12:08
-
-
Save ervitis/4dc439ef34d54ba41834692d862ae382 to your computer and use it in GitHub Desktop.
hennge test
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bufio" | |
"bytes" | |
"io" | |
"io/ioutil" | |
"log" | |
"os" | |
"strconv" | |
"strings" | |
"sync" | |
) | |
/* | |
Notes: as the assessment says all the input data has a min and max value so I decided to use a slice data struct to | |
store each line of integer numbers. If we wouldn't know the limit (or it is very big) I would consider using channels with | |
go routines and read them one by one using a fanIn-fanOut pattern. | |
For example: | |
items := make(chan int, 1) | |
complete := make(chan bool) | |
go func() { | |
// inside a loop to read each item | |
items <- readItemFromLine() | |
// after the loop | |
close(items) | |
} | |
... | |
// inside another loop of the queue to get each item and then send the complete signal | |
item := <-items | |
sumSquare += item*item | |
... | |
complete <- true | |
// in another part of the code I would control the complete channel to finish each go routine | |
*/ | |
type ( | |
inputData struct { | |
numberItems int | |
items []int | |
sumSquares int | |
} | |
) | |
const ( | |
TESTINGENABLE = "TEST" | |
TESTINGFILENAME = "TESTFILENAME" | |
TESTINGOUTPUTFILENAME = "TESTFILENAMEOUTPUT" | |
) | |
var ( | |
testCase []*inputData | |
mtx sync.Mutex | |
) | |
func readInput(reader *bufio.Reader) (string, error) { | |
mtx.Lock() | |
defer mtx.Unlock() | |
line, _, err := reader.ReadLine() | |
if err != nil { | |
return "", err | |
} | |
return string(line), nil | |
} | |
func convertStringItemsToIntItems(items []string) ([]int, error) { | |
n := len(items) | |
data := make([]int, 0) | |
LOOP: | |
if n > 0 { | |
input, err := strconv.Atoi(items[len(items)-n]) | |
if err != nil { | |
return nil, err | |
} | |
data = append(data, input) | |
n-- | |
goto LOOP | |
} | |
return data, nil | |
} | |
func getBufferReaderFromEnviron() *bufio.Reader { | |
envTest := os.Getenv(TESTINGENABLE) | |
if envTest == "" { | |
return bufio.NewReader(os.Stdin) | |
} | |
fileName := os.Getenv(TESTINGFILENAME) | |
if fileName == "" { | |
fileName = "tests_cases.txt" | |
} | |
buff, _ := ioutil.ReadFile(fileName) | |
return bufio.NewReader(bytes.NewBuffer(buff)) | |
} | |
func getInputData() ([]*inputData, error) { | |
reader := getBufferReaderFromEnviron() | |
INITINPUTDATA: | |
input, err := readInput(reader) | |
if err != nil { | |
return nil, err | |
} | |
input = strings.TrimSpace(input) | |
if input == "" { | |
goto INITINPUTDATA | |
} | |
numberTestCases, err := strconv.Atoi(input) | |
if err != nil { | |
return nil, err | |
} | |
INPUTLOOP: | |
if numberTestCases > 0 { | |
input, err = readInput(reader) | |
if err != nil { | |
return nil, err | |
} | |
input = strings.TrimSpace(input) | |
numberItems, err := strconv.Atoi(input) | |
if err != nil { | |
return nil, err | |
} | |
if numberItems == 0 { | |
_, _ = readInput(reader) | |
numberTestCases-- | |
goto INPUTLOOP | |
} | |
input, err = readInput(reader) | |
if err != nil { | |
return nil, err | |
} | |
input = strings.TrimSpace(input) | |
items, err := convertStringItemsToIntItems(strings.Split(input, " ")) | |
if err != nil { | |
return nil, err | |
} | |
mtx.Lock() | |
data := &inputData{ | |
numberItems: numberItems, | |
items: items, | |
} | |
testCase = append(testCase, data) | |
mtx.Unlock() | |
numberTestCases-- | |
goto INPUTLOOP | |
} | |
return testCase, nil | |
} | |
func calculateSumSquares(data []*inputData) { | |
mtx.Lock() | |
defer mtx.Unlock() | |
n := len(data) | |
LOOPTESTCASES: | |
if n > 0 { | |
i := len(data) - n | |
m := len(data[i].items) | |
LOOPITEMS: | |
if m > 0 { | |
j := len(data[i].items) - m | |
if data[i].items[j] > 0 { | |
data[i].sumSquares += data[i].items[j] * data[i].items[j] | |
} | |
m-- | |
goto LOOPITEMS | |
} | |
n-- | |
goto LOOPTESTCASES | |
} | |
} | |
func printResult(data []*inputData, printer io.ReadWriter) { | |
mtx.Lock() | |
n := len(data) | |
LOOPTESTCASES: | |
if n > 0 { | |
_, _ = printer.Write([]byte(strconv.Itoa(data[len(data)-n].sumSquares) + "\n")) | |
n-- | |
goto LOOPTESTCASES | |
} | |
mtx.Unlock() | |
} | |
func setOutputStream() (*os.File, error) { | |
testEnable := os.Getenv(TESTINGENABLE) | |
if testEnable == "" { | |
return os.Stdout, nil | |
} | |
testOutputFileName := os.Getenv(TESTINGOUTPUTFILENAME) | |
if testOutputFileName == "" { | |
return os.Stdout, nil | |
} | |
f, err := os.OpenFile(testOutputFileName, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0755) | |
if err != nil { | |
return nil, err | |
} | |
return f, err | |
} | |
func main() { | |
testCase = make([]*inputData, 0) | |
input, err := getInputData() | |
if err != nil { | |
log.Fatalf("An error happened! %s", err.Error()) | |
} | |
calculateSumSquares(input) | |
outputStream, err := setOutputStream() | |
if err != nil { | |
log.Fatalf("An error happened trying open an output stream %s", err.Error()) | |
} | |
defer outputStream.Close() | |
printResult(input, outputStream) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment