1.3 找出重复行 (Go程序设计语言)

267 阅读2分钟

用于文件复制、打印、检索、排序、统计的程序,通常有一个相似的结构:在输入接口上循环读取,然后对每一个元素进行一些计算,在运行时或者在最后输出结果。我们展示三个版本的dup程序,它受UNIX的uniq命令启发来找到相邻的重复行。这个程序使用容易适配的结构和包。 第一个版本的dup程序输出标准输入中出现次数大于1的行,前面是次数。这个程序引入if语句、map类型和bufio包。

gop1.io/ch1/dup1

package main

import (
   "bufio"
   "fmt"
   "os"
)

func main() {
   counts := make(map[string]int)
   input := bufio.NewScanner(os.Stdin)
   for input.Scan() {
      counts[input.Text()]++
   }
   //注意:忽略input.Err()中可能的错误
   for line, n := range counts {
      if n > 1 {
         fmt.Println("%d\t%s\n", n, line)
      }
   }
}

像for一样,if语句中的条件部分也从不放在圆括号里面,但是程序体中需要用到大括号。这里还有一个可选的else部分,当条件为false的时候执行。

map存储一个键/值对集合,并且提供常量时间的操作来存储、获取或测试集合中的某个元素。键可以是其值能够进行相等(==)比较的任意类型,字符串是最常见的例子;值可以是任意类型。这个例子中,键的类型是字符串,值是int。内置的函数make可以用来新建map,它还可以有其他用途。map将在4.3节中进行更多讨论

每次dup从输入读取一行内容,这一行就作为map中的键,对应的值递增1。语句counts[intput.Text()]++等价于下面的两个语句:

    line := input.Text()
    counts[line] = counts[line] + 1

键在map中不存在时也是没有问题的。当一个新的行第一次出现时,右边的表达式counts[line]个面具值类型被推演为零值,int的零值是0

为了输出结果,我们使用基于range的for循环,这次在map类型的counts