Freq produces only the unique lines from the pipe's contents, each prefixed with a frequency count, in descending numerical order (most frequent lines first). Lines with equal frequency will be sorted alphabetically. For example, we could take a common shell pipeline like this: sort input.txt |un
()
| 615 | // Like Unix uniq(1), Freq right-justifies its count values in a column for |
| 616 | // readability, padding with spaces if necessary. |
| 617 | func (p *Pipe) Freq() *Pipe { |
| 618 | freq := map[string]int{} |
| 619 | type frequency struct { |
| 620 | line string |
| 621 | count int |
| 622 | } |
| 623 | return p.Filter(func(r io.Reader, w io.Writer) error { |
| 624 | scanner := newScanner(r) |
| 625 | for scanner.Scan() { |
| 626 | freq[scanner.Text()]++ |
| 627 | } |
| 628 | freqs := make([]frequency, 0, len(freq)) |
| 629 | max := 0 |
| 630 | for line, count := range freq { |
| 631 | freqs = append(freqs, frequency{line, count}) |
| 632 | if count > max { |
| 633 | max = count |
| 634 | } |
| 635 | } |
| 636 | sort.Slice(freqs, func(i, j int) bool { |
| 637 | x, y := freqs[i].count, freqs[j].count |
| 638 | if x == y { |
| 639 | return freqs[i].line < freqs[j].line |
| 640 | } |
| 641 | return x > y |
| 642 | }) |
| 643 | fieldWidth := len(strconv.Itoa(max)) |
| 644 | for _, item := range freqs { |
| 645 | fmt.Fprintf(w, "%*d %s\n", fieldWidth, item.count, item.line) |
| 646 | } |
| 647 | return nil |
| 648 | }) |
| 649 | } |
| 650 | |
| 651 | // Get makes an HTTP GET request to url, sending the contents of the pipe as |
| 652 | // the request body, and produces the server's response. See [Pipe.Do] for how |