60 lines
		
	
	
		
			1.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			60 lines
		
	
	
		
			1.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package main
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"strconv"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| // domain represents a domain log record
 | |
| type domain struct {
 | |
| 	name   string
 | |
| 	visits int
 | |
| }
 | |
| 
 | |
| // parser parses a log file and provides an iterator to iterate upon the domains
 | |
| //
 | |
| // the parser struct is carefully crafted to be usable using its zero values except the map field
 | |
| type parser struct {
 | |
| 	sum     map[string]int // visits per unique domain
 | |
| 	domains []domain       // unique domain names
 | |
| 	total   int            // total visits to all domains
 | |
| 	lines   int            // number of parsed lines (for the error messages)
 | |
| }
 | |
| 
 | |
| // newParser creates and returns a new parser.
 | |
| func newParser() parser {
 | |
| 	return parser{sum: make(map[string]int)}
 | |
| }
 | |
| 
 | |
| // parse parses the given text and returns a domain struct
 | |
| func parse(p parser, line string) (dom domain, err error) {
 | |
| 	fields := strings.Fields(line)
 | |
| 	if len(fields) != 2 {
 | |
| 		err = fmt.Errorf("wrong input: %v (line #%d)", fields, p.lines)
 | |
| 		return
 | |
| 	}
 | |
| 	name, visits := fields[0], fields[1]
 | |
| 
 | |
| 	n, err := strconv.Atoi(visits)
 | |
| 	if n < 0 || err != nil {
 | |
| 		err = fmt.Errorf("wrong input: %q (line #%d)", visits, p.lines)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	return domain{name: name, visits: n}, nil
 | |
| }
 | |
| 
 | |
| // push pushes the given domain to the internal list of domains.
 | |
| // it also increases the total visits for all the domains.
 | |
| func push(p parser, d domain) parser {
 | |
| 	if _, ok := p.sum[d.name]; !ok {
 | |
| 		p.domains = append(p.domains, d)
 | |
| 	}
 | |
| 
 | |
| 	p.sum[d.name] += d.visits
 | |
| 	p.total += d.visits
 | |
| 
 | |
| 	return p
 | |
| }
 |