analytics.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. package main
  2. import (
  3. "sort"
  4. "strings"
  5. )
  6. type analytic struct {
  7. Key string
  8. Count int
  9. Percentage float64
  10. Items []analytic `json:",omitempty"`
  11. }
  12. type analyticList []analytic
  13. func (l analyticList) Less(a, b int) bool {
  14. if l[a].Key == "Others" {
  15. return true
  16. }
  17. if l[b].Key == "Others" {
  18. return false
  19. }
  20. return l[b].Count < l[a].Count // inverse
  21. }
  22. func (l analyticList) Swap(a, b int) {
  23. l[a], l[b] = l[b], l[a]
  24. }
  25. func (l analyticList) Len() int {
  26. return len(l)
  27. }
  28. // Returns a list of frequency analytics for a given list of strings.
  29. func analyticsFor(ss []string, cutoff int) []analytic {
  30. m := make(map[string]int)
  31. t := 0
  32. for _, s := range ss {
  33. m[s]++
  34. t++
  35. }
  36. l := make([]analytic, 0, len(m))
  37. for k, c := range m {
  38. l = append(l, analytic{
  39. Key: k,
  40. Count: c,
  41. Percentage: 100 * float64(c) / float64(t),
  42. })
  43. }
  44. sort.Sort(analyticList(l))
  45. if cutoff > 0 && len(l) > cutoff {
  46. c := 0
  47. for _, i := range l[cutoff:] {
  48. c += i.Count
  49. }
  50. l = append(l[:cutoff], analytic{
  51. Key: "Others",
  52. Count: c,
  53. Percentage: 100 * float64(c) / float64(t),
  54. })
  55. }
  56. return l
  57. }
  58. func statsForInts(data []int) [4]float64 {
  59. var res [4]float64
  60. if len(data) == 0 {
  61. return res
  62. }
  63. sort.Ints(data)
  64. res[0] = float64(data[int(float64(len(data))*0.05)])
  65. res[1] = float64(data[len(data)/2])
  66. res[2] = float64(data[int(float64(len(data))*0.95)])
  67. res[3] = float64(data[len(data)-1])
  68. return res
  69. }
  70. func statsForFloats(data []float64) [4]float64 {
  71. var res [4]float64
  72. if len(data) == 0 {
  73. return res
  74. }
  75. sort.Float64s(data)
  76. res[0] = data[int(float64(len(data))*0.05)]
  77. res[1] = data[len(data)/2]
  78. res[2] = data[int(float64(len(data))*0.95)]
  79. res[3] = data[len(data)-1]
  80. return res
  81. }
  82. func group(by func(string) string, as []analytic, perGroup int) []analytic {
  83. var res []analytic
  84. next:
  85. for _, a := range as {
  86. group := by(a.Key)
  87. for i := range res {
  88. if res[i].Key == group {
  89. res[i].Count += a.Count
  90. res[i].Percentage += a.Percentage
  91. if len(res[i].Items) < perGroup {
  92. res[i].Items = append(res[i].Items, a)
  93. }
  94. continue next
  95. }
  96. }
  97. res = append(res, analytic{
  98. Key: group,
  99. Count: a.Count,
  100. Percentage: a.Percentage,
  101. Items: []analytic{a},
  102. })
  103. }
  104. sort.Sort(analyticList(res))
  105. return res
  106. }
  107. func byVersion(s string) string {
  108. parts := strings.Split(s, ".")
  109. if len(parts) >= 2 {
  110. return strings.Join(parts[:2], ".")
  111. }
  112. return s
  113. }
  114. func byPlatform(s string) string {
  115. parts := strings.Split(s, "-")
  116. if len(parts) >= 2 {
  117. return parts[0]
  118. }
  119. return s
  120. }
  121. func byCompiler(s string) string {
  122. if strings.HasPrefix(s, "go1.") && len(s) >= 5 {
  123. return s[:5]
  124. }
  125. return "Other"
  126. }