init
This commit is contained in:
commit
7a6b109e78
4 changed files with 164 additions and 0 deletions
32
cmd/namecount/main.go
Normal file
32
cmd/namecount/main.go
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"tallin/internal/counter"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if len(os.Args) != 2 {
|
||||||
|
fmt.Fprintf(os.Stderr, "usage: %s <filename>\n", os.Args[0])
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.Open(os.Args[1])
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "open file: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
counts, err := counter.Count(file)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "read file: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, result := range counter.Sorted(counts) {
|
||||||
|
fmt.Printf("%s:%d\n", result.Name, result.Count)
|
||||||
|
}
|
||||||
|
}
|
||||||
3
go.mod
Normal file
3
go.mod
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
module tallin
|
||||||
|
|
||||||
|
go 1.22
|
||||||
53
internal/counter/counter.go
Normal file
53
internal/counter/counter.go
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
package counter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"io"
|
||||||
|
"sort"
|
||||||
|
)
|
||||||
|
|
||||||
|
const maxLineSize = 1024 * 1024
|
||||||
|
|
||||||
|
type Result struct {
|
||||||
|
Name string
|
||||||
|
Count int
|
||||||
|
}
|
||||||
|
|
||||||
|
func Count(r io.Reader) (map[string]int, error) {
|
||||||
|
counts := make(map[string]int)
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(r)
|
||||||
|
scanner.Buffer(make([]byte, 64*1024), maxLineSize)
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
name := scanner.Text()
|
||||||
|
if name == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
counts[name]++
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return counts, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Sorted(counts map[string]int) []Result {
|
||||||
|
results := make([]Result, 0, len(counts))
|
||||||
|
for name, count := range counts {
|
||||||
|
results = append(results, Result{Name: name, Count: count})
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(results, func(i, j int) bool {
|
||||||
|
if results[i].Count != results[j].Count {
|
||||||
|
return results[i].Count > results[j].Count
|
||||||
|
}
|
||||||
|
|
||||||
|
return results[i].Name < results[j].Name
|
||||||
|
})
|
||||||
|
|
||||||
|
return results
|
||||||
|
}
|
||||||
76
internal/counter/counter_test.go
Normal file
76
internal/counter/counter_test.go
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
package counter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCount(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
counts, err := Count(strings.NewReader("Алена\nМиша\nАлена\nДима\n\n"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Count() error = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
want := map[string]int{
|
||||||
|
"Алена": 2,
|
||||||
|
"Миша": 1,
|
||||||
|
"Дима": 1,
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(counts, want) {
|
||||||
|
t.Fatalf("Count() = %#v, want %#v", counts, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCountPreservesSpaces(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
counts, err := Count(strings.NewReader("Anna\n Anna \nAnna\n"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Count() error = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
want := map[string]int{
|
||||||
|
"Anna": 2,
|
||||||
|
" Anna ": 1,
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(counts, want) {
|
||||||
|
t.Fatalf("Count() = %#v, want %#v", counts, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCountEmptyInput(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
counts, err := Count(strings.NewReader("\n\n"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Count() error = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(counts) != 0 {
|
||||||
|
t.Fatalf("Count() = %#v, want empty map", counts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSorted(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
counts := map[string]int{
|
||||||
|
"Миша": 1,
|
||||||
|
"Алена": 2,
|
||||||
|
"Дима": 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
got := Sorted(counts)
|
||||||
|
want := []Result{
|
||||||
|
{Name: "Алена", Count: 2},
|
||||||
|
{Name: "Дима", Count: 1},
|
||||||
|
{Name: "Миша", Count: 1},
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(got, want) {
|
||||||
|
t.Fatalf("Sorted() = %#v, want %#v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue