Home > Net >  Sorting slice of structs by big.Int value
Sorting slice of structs by big.Int value

Time:08-14

I have a list of structs which should be sorted by the fee value of the structs. I couldn't use big.Int and big.Float because sort.Slice won't work with these types. Therefore I created the compareAmount variable which is the converted float version of fee and use that for the sorting. The problem is that an integer overflow happens (I assume), therefore I get wrong results. The below attached code produces the following output:

-2530185498501831 -2.530185498501831e 18
-1018378616691543 -1.018378616691543e 18
-867409028382366 -8.67409028382366e 17
-288718783870437 -2.88718783870437e 17
-190626693543325 -1.90626693543325e 17
-15553651457149158 2.8930926165603937e 18

The objects should be listed from high to low, so I believe the correct result would be if -190626693543325 would be the first element, than -288718783870437 the second as these are closest to 0. But something happens when I convert the numbers and the list is not sorted as I wanted. So my question is that how could I sort my slice of structs based on the big.Int values and produce this output:

-190626693543325 -1.90626693543325e 17
-288718783870437 -2.88718783870437e 17
-867409028382366 -8.67409028382366e 17
-1018378616691543 -1.018378616691543e 18
-2530185498501831 -2.530185498501831e 18
-15553651457149158 2.8930926165603937e 18

Playground link

package main

import (
    "fmt"
    "math/big"
    "sort"
)

func divBigInt(num *big.Int) *big.Int {
    divider := big.NewInt(1000)
    divided := big.NewInt(0).Mul(num, divider)
    return divided
}

type compareStruct struct {
    fee           *big.Int
    compareAmount float64
}

func main() {

    fee1 := big.NewInt(-288718783870437)
    fee2 := big.NewInt(-867409028382366)
    fee3 := big.NewInt(-190626693543325)
    fee4 := big.NewInt(-1018378616691543)
    fee5 := big.NewInt(-15553651457149158)
    fee6 := big.NewInt(-2530185498501831)

    fees := make([]*big.Int, 0)
    fees = append(fees, fee1)
    fees = append(fees, fee2)
    fees = append(fees, fee3)
    fees = append(fees, fee4)
    fees = append(fees, fee5)
    fees = append(fees, fee6)

    feeList := make([]compareStruct, 0)

    for _, f := range fees {
        i1 := compareStruct{fee: f, compareAmount: float64(divBigInt(f).Int64())}
        feeList = append(feeList, i1)
    }

    sort.Slice(feeList, func(i, j int) bool {
        return feeList[i].compareAmount < feeList[j].compareAmount
    })
    for _, x := range feeList {

        fmt.Println(x.fee, x.compareAmount)

    }
}

CodePudding user response:

big.Int has an Int.Cmp() method, so you can compare them, so you can directly sort big.Int values without any conversion. To sort them descendant to get your desired output:

sort.Slice(feeList, func(i, j int) bool {
    return feeList[i].fee.Cmp(feeList[j].fee) > 0
})

Try it on the Go Playground.

Also, if you just want to sort the numbers, the slice of wrapper structs is also needless, you can sort a slice of *big.Int similarly.

CodePudding user response:

You can avoid the need for the float64 field and just sort the numbers directly:

package main

import (
    "fmt"
    "math/big"
    "sort"
)

func main() {
    fees := []*big.Int{
        big.NewInt(-288718783870437),
        big.NewInt(-867409028382366),
        big.NewInt(-190626693543325),
        big.NewInt(-1018378616691543),
        big.NewInt(-15553651457149158),
        big.NewInt(-2530185498501831),
    }
    sort.Slice(fees, func(a, b int) bool {
        // sort direction high before low.
        return fees[a].Cmp(fees[b]) > 0
    })
    fmt.Println("fees", fees)
}
  • Related