Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Week 1 - Exercise #32

Open
tpphu opened this issue May 24, 2020 · 2 comments
Open

Week 1 - Exercise #32

tpphu opened this issue May 24, 2020 · 2 comments

Comments

@tpphu
Copy link
Owner

tpphu commented May 24, 2020

Unit 1

Convert CSV file to YAML file.

Input:

Data

Output:

Output

Unit 2

Port 5 functions of Lodash to Golang

  • IsEmpty
  • Last
  • Map
  • Contains
  • Max
@tpphu
Copy link
Owner Author

tpphu commented May 27, 2020

Version 2, để code nhìn rõ ràng hơn.

package convert

import (
	"bufio"
	"errors"
	"os"
	"strconv"
	"strings"
)

type City struct {
	ID        int
	Name      string
	Districts []*District
}

type District struct {
	ID    int
	Name  string
	Wards []Ward
}

type Ward struct {
	ID   int
	Name string
}

var InvalidCSVData = errors.New("Invalid CSV Data")
var InvalidParseIDCity = errors.New("Invalid Parse ID City")
var InvalidParseIDDistrict = errors.New("Invalid Parse ID District")
var InvalidParseIDWard = errors.New("Invalid Parse ID Ward")

var citiMap = map[int]*City{}
var districtMap = map[int]*District{}

func processCity(cities *[]*City, id string, name string) (*City, error) {
	ID, err := strconv.Atoi(id) //int
	if err != nil {
		return nil, InvalidParseIDCity
	}
	city, ok := citiMap[ID]
	if !ok {
		city = &City{
			Name: name,
			ID:   ID,
		}
		citiMap[ID] = city
		*cities = append(*cities, city)
	}
	return city, nil
}

func processDistrict(city *City, id string, name string) (*District, error) {
	ID, err := strconv.Atoi(id) //int
	if err != nil {
		return nil, InvalidParseIDDistrict
	}
	district, ok := districtMap[ID]
	if !ok {
		district = &District{
			Name: name,
			ID:   ID,
		}
		districtMap[ID] = district
		city.Districts = append(city.Districts, district)
	}
	return district, nil
}

func processWard(district *District, id string, name string) error {
	ID, err := strconv.Atoi(id) //int
	if err != nil {
		return InvalidParseIDWard
	}
	ward := Ward{
		Name: name,
		ID:   ID,
	}
	district.Wards = append(district.Wards, ward)
	return nil
}

// Private
func ConvertCSV2Yaml(file string) (cities []*City, err error) {
	inFile, err := os.Open(file)
	if err != nil {
		return cities, err
	}
	// Hoc bua sau
	defer inFile.Close()
	//
	scanner := bufio.NewScanner(inFile)
	isFirstLine := false
	for scanner.Scan() {
		line := scanner.Text()
		if isFirstLine == false {
			isFirstLine = true
			continue
		}
		cells := strings.Split(line, ",")
		if len(cells) < 6 {
			return cities, InvalidCSVData
		}
		// Xu ly cai city
		city, err := processCity(&cities, cells[1], cells[0])
		if err != nil {
			return cities, err
		}
		// Xu ly district
		district, err := processDistrict(city, cells[3], cells[2])
		if err != nil {
			return cities, InvalidParseIDDistrict
		}
		// Xu ly ward
		err = processWard(district, cells[5], cells[4])
		if err != nil {
			return cities, InvalidParseIDWard
		}
	}
	return cities, nil
}

@tpphu
Copy link
Owner Author

tpphu commented May 27, 2020

Version 3, phiên bản tổ chức tốt hơn

package convert

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

type City struct {
	ID        int
	Name      string
	Districts []*District
}

type District struct {
	ID    int
	Name  string
	Wards []*Ward
}

type Ward struct {
	ID   int
	Name string
}

type InvalidParserError interface {
	error
	GetTypeData() string
	GetRawData() []string
}

type invalidParserErrorImp struct {
	typeData string
	rawData  []string
}

func (e invalidParserErrorImp) Error() string {
	return fmt.Sprintf("Invalid parser for %s, raw data are: %s",
		e.typeData,
		strings.Join(e.rawData, ","))
}

func (e invalidParserErrorImp) GetTypeData() string {
	return e.typeData
}

func (e invalidParserErrorImp) GetRawData() []string {
	return e.rawData
}

func NewInvalidParserError(typeData string, data ...string) InvalidParserError {
	return invalidParserErrorImp{
		typeData: typeData,
		rawData:  data,
	}
}

var InvalidCSVData = func(data ...string) InvalidParserError {
	return invalidParserErrorImp{
		typeData: "line",
		rawData:  data,
	}
}
var InvalidParseIDCity = func(data ...string) InvalidParserError {
	return invalidParserErrorImp{
		typeData: "city",
		rawData:  data,
	}
}
var InvalidParseIDDistrict = func(data ...string) InvalidParserError {
	return invalidParserErrorImp{
		typeData: "district",
		rawData:  data,
	}
}
var InvalidParseIDWard = func(data ...string) InvalidParserError {
	return invalidParserErrorImp{
		typeData: "ward",
		rawData:  data,
	}
}

type CSVToYaml struct {
	citiMap     map[int]*City
	districtMap map[int]*District
	result      []*City
}

func NewCSVToYamlConverter() CSVToYaml {
	converter := CSVToYaml{
		citiMap:     map[int]*City{},
		districtMap: map[int]*District{},
	}
	return converter
}
func (c *CSVToYaml) ConvertCSV2Yaml(file string) ([]*City, error) {
	inFile, err := os.Open(file)
	if err != nil {
		return c.result, err
	}
	// Hoc bua sau
	defer inFile.Close()
	//
	scanner := bufio.NewScanner(inFile)
	isFirstLine := false
	for scanner.Scan() {
		line := scanner.Text()
		if isFirstLine == false {
			isFirstLine = true
			continue
		}
		err := c.process(line)
		if err != nil {
			return c.result, err
		}
	}
	return c.result, nil
}

func (c *CSVToYaml) process(line string) InvalidParserError {
	cells := strings.Split(line, ",")
	if len(cells) < 6 {
		return InvalidCSVData(cells...)
	}
	// Xu ly cai city
	city, err := c.processCity(cells[1], cells[0])
	if err != nil {
		return err
	}
	// Xu ly district
	district, err := c.processDistrict(city, cells[3], cells[2])
	if err != nil {
		return err
	}
	// Xu ly ward
	_, err = c.processWard(district, cells[5], cells[4])
	return err
}

func (c *CSVToYaml) processCity(id string, name string) (*City, InvalidParserError) {
	ID, err := strconv.Atoi(id) //int
	if err != nil {
		return nil, InvalidParseIDCity(id, name)
	}
	city, ok := c.citiMap[ID]
	if !ok {
		city = &City{
			Name: name,
			ID:   ID,
		}
		c.citiMap[ID] = city
		c.result = append(c.result, city)
	}
	return city, nil
}

func (c *CSVToYaml) processDistrict(city *City, id string, name string) (*District, InvalidParserError) {
	ID, err := strconv.Atoi(id) //int
	if err != nil {
		return nil, InvalidParseIDDistrict(id, name)
	}
	district, ok := c.districtMap[ID]
	if !ok {
		district = &District{
			Name: name,
			ID:   ID,
		}
		c.districtMap[ID] = district
		city.Districts = append(city.Districts, district)
	}
	return district, nil
}

func (c *CSVToYaml) processWard(district *District, id string, name string) (*Ward, InvalidParserError) {
	ID, err := strconv.Atoi(id) //int
	if err != nil {
		return nil, InvalidParseIDWard(id, name)
	}
	ward := &Ward{
		Name: name,
		ID:   ID,
	}
	district.Wards = append(district.Wards, ward)
	return ward, nil
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant