Skip to content

Instantly share code, notes, and snippets.

@yarrom
Created May 8, 2019 08:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yarrom/bcd9c62e58463e2acc0a7efcb6a081fb to your computer and use it in GitHub Desktop.
Save yarrom/bcd9c62e58463e2acc0a7efcb6a081fb to your computer and use it in GitHub Desktop.
Go beats Rust in benchmark from here https://habr.com/ru/post/450512/
package main
import (
"bufio"
"fmt"
"github.com/json-iterator/go"
"os"
"reflect"
"strconv"
"time"
)
func scan_file(r *bufio.Reader) error {
var (
// Read buffer
aBufRead []byte = make([]byte, 4096)
b byte
// Buffer for accumulating string values
aBuf [256]byte
// Bytes in buffer
nBuf int = 0
nBraces int = 0
nRead int
err error
bLBrace,
bRBrace bool
json = jsoniter.ConfigCompatibleWithStandardLibrary
data interface{}
)
for {
nRead, _ = r.Read(aBufRead)
if nRead == 0 {
break
}
for i := 0; i < nRead; i++ {
b = aBufRead[i]
bLBrace = b == '{'
bRBrace = b == '}'
if bLBrace {
nBraces++
}
if bRBrace {
nBraces--
}
if bLBrace || bRBrace || (!bLBrace && !bRBrace && (nBraces > 0)) {
if nBuf >= len(aBuf) {
return fmt.Errorf("Longer buffer neded >%d", nBuf)
}
aBuf[nBuf] = b
nBuf++
}
if bRBrace && (nBraces == 0) {
err = json.Unmarshal(aBuf[0:nBuf], &data)
if err != nil {
return err
}
process_object(&data)
nBuf = 0
}
}
}
return nil
}
// Source data
type DebtRec struct {
company string
phones []string
debt float64
}
// Result data
type Debtor struct {
companies map[string]bool
phones map[string]bool
debt float64
}
type Debtors struct {
all []Debtor
index_by_phone map[string]int
}
func extract_data(obj *interface{}, dr *DebtRec) {
switch v := (*obj).(type) {
case map[string]interface{}:
switch w := v["company"].(type) {
case map[string]interface{}:
if val, ok := w["name"]; ok {
dr.company = val.(string)
}
case string:
dr.company = w
default:
fmt.Printf("company is unknown: %T, %v\n", w, w)
}
switch w := v["debt"].(type) {
case float64:
dr.debt = w
case string:
var err error
dr.debt, err = strconv.ParseFloat(w, 64)
if err != nil {
panic(err)
}
default:
fmt.Printf("debt is unknown: %T, %v\n", w, w)
}
switch w := v["phones"].(type) {
case float64:
dr.phones = append(dr.phones, fmt.Sprintf("%.0f", w))
case []interface{}:
for _, val := range w {
switch z := val.(type) {
case float64:
dr.phones = append(dr.phones, fmt.Sprintf("%.0f", z))
case string:
dr.phones = append(dr.phones, z)
default:
fmt.Printf("phone is unknown: %T, %v\n", z, z)
}
}
default:
fmt.Printf("phones is unknown: %T, %v\n", w, w)
}
if val, ok := v["phone"]; ok {
switch w := val.(type) {
case float64:
dr.phones = append(dr.phones, fmt.Sprintf("%.0f", w))
default:
fmt.Printf("phone is unknown: %T, %v\n", w, w)
}
}
default:
fmt.Printf("object is unknown: %T, %v\n", v, v)
}
}
func process_object(obj *interface{}) {
var dr DebtRec
extract_data(obj, &dr)
var bFound bool = false
var di int // Debtor index search result
for _, p := range dr.phones {
if di, bFound = debtors.index_by_phone[p]; bFound {
break
}
}
if bFound { // Existing debtor
var d *Debtor = &debtors.all[di]
if _, ok := d.companies[dr.company]; !ok {
d.companies[dr.company] = true
}
for _, p := range dr.phones {
if _, ok := d.phones[p]; !ok {
d.phones[p] = true
}
debtors.index_by_phone[p] = di
}
d.debt += dr.debt
} else { // New debtor
var d Debtor = Debtor{}
d.companies = make(map[string]bool)
d.phones = make(map[string]bool)
di = len(debtors.all)
d.companies[dr.company] = true
for _, p := range dr.phones {
d.phones[p] = true
debtors.index_by_phone[p] = di
}
d.debt = dr.debt
debtors.all = append(debtors.all, d)
}
}
func process_file(sName string) {
var (
err error
f *os.File
)
f, err = os.Open(sName)
check(err)
defer f.Close()
err = scan_file(bufio.NewReaderSize(f, 16384))
check(err)
}
func check(err error) {
if err != nil {
panic(err)
}
}
var debtors Debtors
func main() {
debtors = Debtors{}
debtors.index_by_phone = make(map[string]int)
t := time.Now()
process_file("1.JSON")
var ft float32 = float32(time.Since(t)) / float32(time.Second)
var keys []reflect.Value
for i := 0; i < len(debtors.all); i++ {
fmt.Printf("Company names:\t")
keys = reflect.ValueOf(debtors.all[i].companies).MapKeys()
for j := 0; j < len(keys); j++ {
fmt.Printf("%s", keys[j])
if j != len(keys)-1 {
fmt.Printf(", ")
} else {
fmt.Printf("\n")
}
}
fmt.Printf("Total debt:\t%.0f\n", debtors.all[i].debt)
fmt.Printf("Phone numbers:\t")
keys = reflect.ValueOf(debtors.all[i].phones).MapKeys()
for j := 0; j < len(keys); j++ {
fmt.Printf("%s", keys[j])
if j != len(keys)-1 {
fmt.Printf(", ")
} else {
fmt.Printf("\n")
}
}
fmt.Printf("\n")
}
fmt.Printf("Total time:\t%.3f s\n", ft)
}
/*
Company names: Первая коллекторская, Шестерочка, Рога и копыта
Total debt: 910000000
Phone numbers: 2128506, 789, 788, 123, 234, 456
Company names: Святой престол, Казачий спас
Total debt: 433200000
Phone numbers: 345678, 666, 234567
Total time: 3.519 s
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment