I have been going through The go programming language book and I got stuck trying to come up with a solution for one of the exercises.
Exercise 1.4, available here, starts with dup2 a program that reads either user input from stdin or from a sequence of named files and prints out the number of duplicate lines.Dup2 can be found here.
Such that
./dup2 file.txt file2.txt
5 cat
5 dog
Where
$cat file.txt && echo && cat file2.txt
cat
cat
dog
dog
cat
cat
cat
dog
dog
dog
In the exercise the reader is asked to
Modify dup2 to print the names of all the files in which each duplicated line occurs.
I think the idea is to keep the set of files where it occurs for each word. You would need to modify the counts map (currently string -> integer) to something that maps from string to a structure that contains both the count and set of file names.
Hi @calmh
So i thought about how i would be able to create such a structure,did some research and found out the strucutre you are describing is a nested map!
With that i was able to create a nested map that looked like this map[fileName:map[line:count]].Now i’m able to get the name of a file together with its duplicate line count and print out only the files with duplicate lines.
Here is the full code
package main
import (
"bufio"
"fmt"
"os"
)
var files []string = os.Args[1:]
var linesStdin = map[string]int{}
var counts = map[string]map[string]int{}
func main() {
if len(files) == 0 {
countStdin(os.Stdin, linesStdin)
for line, n := range linesStdin {
if n > 1 {
fmt.Printf("%s\t%d\n", line, n)
}
}
} else {
for _, arg := range files {
counts[arg] = map[string]int{}
f, err := os.Open(arg)
if err != nil {
fmt.Fprintf(os.Stderr, "dup2: %v\n", err)
continue
}
countLines(f, counts)
f.Close()
}
for fileName, innerMap := range counts {
for line, n := range innerMap {
if n > 1 {
fmt.Printf("%s\t%s\t%d\n", fileName, line, n)
}
}
}
}
}
func countStdin(f *os.File, linesStdin map[string]int) {
input := bufio.NewScanner(f)
for input.Scan() {
linesStdin[input.Text()]++
}
}
func countLines(f *os.File, counts map[string]map[string]int) {
input := bufio.NewScanner(f)
for input.Scan() {
counts[f.Name()][input.Text()]++
}
}
What do you think about it and are there any improvements i can make?