Skip to content

Instantly share code, notes, and snippets.

@JoshGutman
Last active July 27, 2021 17:22
Show Gist options
  • Save JoshGutman/fd759115578fd7e19acc838f68b214a9 to your computer and use it in GitHub Desktop.
Save JoshGutman/fd759115578fd7e19acc838f68b214a9 to your computer and use it in GitHub Desktop.
package main
import (
"bufio"
"fmt"
"log"
"os"
"sort"
"strconv"
"strings"
)
type Data struct {
quality int
rname string
}
func main() {
if len(os.Args) != 2 {
log.Fatal(" Invalid command-line args. Correct Usage:\n./sam_filter /path/to/.sam > outputfile.txt")
}
filename := os.Args[1]
best := getBest(filename)
rnames := getRnameNumbers(best)
outputRnameNumbers(rnames)
}
func getBest(filename string) map[string]Data {
file, err := os.Open(filename)
if err != nil {
log.Fatal(err)
}
defer file.Close()
ties := make(map[string]bool)
uniques := make(map[string]map[int]string)
best := make(map[string]Data)
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
// Ignore header
if !strings.HasPrefix(line, "@") {
fields := strings.Split(line, "\t")
quality, _ := strconv.Atoi(fields[4])
// If qname not in ties
if !ties[fields[0]] {
// If a qname with a quality has occurred > 1 time
if _, ok := uniques[fields[0]]; !ok {
uniques[fields[0]] = make(map[int]string)
}
if _, ok := uniques[fields[0]][quality]; ok {
ties[fields[0]] = true
delete(uniques, fields[0])
delete(best, fields[0])
// qname with quality is unique
} else {
uniques[fields[0]][quality] = fields[2]
// If qname in best
if val, ok := best[fields[0]]; ok {
// If current quality > previous best quality
if quality > val.quality {
best[fields[0]] = Data{quality, fields[2]}
}
// If qname is not in bests, just write current qname, quality, and rname
} else {
best[fields[0]] = Data{quality, fields[2]}
}
}
}
}
}
return best
}
func getRnameNumbers(best map[string]Data) map[string]int {
rnames := make(map[string]int)
for _, val := range best {
if _, ok := rnames[val.rname]; ok {
rnames[val.rname] += 1
} else {
rnames[val.rname] = 1
}
}
return rnames
}
func outputRnameNumbers(rnames map[string]int) {
numberMap := make(map[int][]string)
numbers := make([]int, len(rnames))
for key, val := range rnames {
numbers = append(numbers, val)
numberMap[val] = append(numberMap[val], key)
}
sort.Sort(sort.Reverse(sort.IntSlice(numbers)))
out := ""
for _, num := range numbers {
for _, rname := range numberMap[num] {
out += rname + "\t" + strconv.Itoa(num) + "\n"
}
}
fmt.Println(out)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment