Created
May 8, 2019 08:44
-
-
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/
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" | |
"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