mirror of
https://github.com/wahyd4/topx.git
synced 2026-08-09 05:06:02 +10:00
Add logic to use priority heap to implement the logic
This commit is contained in:
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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=
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user