Add logic to use priority heap to implement the logic

This commit is contained in:
2022-03-14 20:19:09 +11:00
parent a93bc029de
commit 288f4ebed8
10 changed files with 240 additions and 2 deletions
+28
View File
@@ -0,0 +1,28 @@
package calculator
type LargestNumbersHeap []int
func (biggestNumbers LargestNumbersHeap) Less(first, second int) bool {
// pop the smallest number
return biggestNumbers[first] < biggestNumbers[second]
}
func (biggestNumbers LargestNumbersHeap) Len() int {
return len(biggestNumbers)
}
func (biggestNumbers LargestNumbersHeap) Swap(first, second int) {
biggestNumbers[first], biggestNumbers[second] = biggestNumbers[second], biggestNumbers[first]
}
func (biggestNumbers *LargestNumbersHeap) Push(x interface{}) {
*biggestNumbers = append(*biggestNumbers, x.(int))
}
func (biggestNumbers *LargestNumbersHeap) Pop() interface{} {
oldNumbers := *biggestNumbers
arrayLength := len(oldNumbers)
number := oldNumbers[arrayLength-1]
*biggestNumbers = oldNumbers[0 : arrayLength-1]
return number
}
+51
View File
@@ -0,0 +1,51 @@
package calculator
import (
"bufio"
"container/heap"
"fmt"
"os"
"strconv"
)
func calculateIncomingNumber(numbers *LargestNumbersHeap, newNumber int) *LargestNumbersHeap {
smallest := heap.Pop(numbers).(int)
if smallest < newNumber {
heap.Push(numbers, newNumber)
} else {
heap.Push(numbers, smallest)
}
return numbers
}
func CalculateLargestNumbers(filePath string, topX int) ([]int, error) {
if topX <= 0 {
return []int{}, nil
}
file, err := os.Open(filePath)
if err != nil {
return []int{}, fmt.Errorf("Could not open file %s with error %w", filePath, err)
}
scanner := bufio.NewScanner(file)
largestNumbersHeap := LargestNumbersHeap{}
for scanner.Scan() {
text := scanner.Text()
number, err := strconv.Atoi(text)
if err != nil {
return []int{}, fmt.Errorf("fail to parse text %s with error %w", text, err)
}
if len(largestNumbersHeap) < topX {
largestNumbersHeap = append(largestNumbersHeap, number)
heap.Init(&largestNumbersHeap)
} else {
calculateIncomingNumber(&largestNumbersHeap, number)
}
}
heap.Init(&largestNumbersHeap)
return largestNumbersHeap, nil
}
+96
View File
@@ -0,0 +1,96 @@
package calculator
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestCalculateLargestNumbers(t *testing.T) {
type args struct {
filePath string
topX int
}
tests := []struct {
name string
args args
want []int
wantErr bool
}{
{
name: "Should return top numbers",
args: args{
filePath: "../test1.txt",
topX: 3,
},
want: []int{0, 2, 5},
wantErr: false,
},
{
name: "Should throw errors",
args: args{
filePath: "../test4.txt",
topX: 3,
},
want: nil,
wantErr: true,
},
{
name: "Should handle duplicate numbers well",
args: args{
filePath: "../test3.txt",
topX: 4,
},
want: []int{23435, 38949, 11111, 11111},
wantErr: false,
},
{
name: "Should return all numbers when topX greater than length of array",
args: args{
filePath: "../test2.txt",
topX: 5,
},
want: []int{1, 9, 3, 2},
wantErr: false,
},
{
name: "Should return 0 when topX is less then 1",
args: args{
filePath: "../test2.txt",
topX: 0,
},
want: []int{},
wantErr: false,
},
{
name: "Should return 0 when topX is less then 1",
args: args{
filePath: "../test2.txt",
topX: -1,
},
want: []int{},
wantErr: false,
},
{
name: "Should throw error when fail to parse file",
args: args{
filePath: "../not_exist.txt",
topX: 3,
},
want: nil,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := CalculateLargestNumbers(tt.args.filePath, tt.args.topX)
if (err != nil) != tt.wantErr {
t.Errorf("CalculateLargestNumbers() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !assert.ElementsMatch(t, got, tt.want) {
t.Errorf("test CalculateLargestNumbers() = %v, want %v", got, tt.want)
}
})
}
}
+8
View File
@@ -1,3 +1,11 @@
module github.com/wahyd4/mryum
go 1.17
require github.com/stretchr/testify v1.7.0
require (
github.com/davecgh/go-spew v1.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
)
+10
View File
@@ -0,0 +1,10 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+17 -2
View File
@@ -1,7 +1,22 @@
package main
import "fmt"
import (
"fmt"
"os"
"github.com/wahyd4/mryum/calculator"
)
const (
filePath = "./testx3.txt"
topNumber = 4
)
func main() {
fmt.Println("hello Mr. Yum")
topNumbers, err := calculator.CalculateLargestNumbers(filePath, topNumber)
if err != nil {
fmt.Println("Oops: " + err.Error())
os.Exit(1)
}
fmt.Printf("Top %d numbers are: %v", topNumber, topNumbers)
}
+6
View File
@@ -0,0 +1,6 @@
0
0
0
2
0
5
+4
View File
@@ -0,0 +1,4 @@
1
9
3
2
+14
View File
@@ -0,0 +1,14 @@
7
1
122
23435
3345
11111
38949
4213
5233
561
11111
6
1
3
+6
View File
@@ -0,0 +1,6 @@
1
s
3
2&&^
3
4