Golang sort.SliceStable在排序后返回不同的结果

huangapple go评论114阅读模式
英文:

Golang sort.SliceStable retrun different result after sort

问题

我使用sort.SliceStable对从txt文件中读取的map[string]int进行排序,但排序后的结果不同。我尝试将map转换为结构体或切片,但都没有成功,这种结果正常吗?

代码:

  1. func TestStableUseSlice() {
  2. counts := make(map[string]int)
  3. f, err := os.Open("/Users/boroughfan/GitDocuments/GoLangPractise/ch01/dup/text_feel_the_light_lyrics.txt")
  4. if err != nil {
  5. fmt.Fprintf(os.Stderr, "dup:%v\n", err)
  6. }
  7. input := bufio.NewScanner(f)
  8. for input.Scan() {
  9. counts[input.Text()]++
  10. }
  11. f.Close()
  12. ///////////////////////////////////////////////////////////
  13. linesSlice := make([]string, 0, len(counts))
  14. for line := range counts {
  15. linesSlice = append(linesSlice, line)
  16. }
  17. sort.SliceStable(linesSlice, func(i, j int) bool {
  18. return counts[linesSlice[i]] < counts[linesSlice[j]]
  19. })
  20. for _, line := range linesSlice {
  21. fmt.Printf("%d\t%s\n", counts[line], line)
  22. }
  23. }
  24. func TestStableUsePair() {
  25. counts := make(map[string]int)
  26. f, err := os.Open("/Users/boroughfan/GitDocuments/GoLangPractise/ch01/dup/text_feel_the_light_lyrics.txt")
  27. if err != nil {
  28. fmt.Fprintf(os.Stderr, "dup:%v\n", err)
  29. }
  30. input := bufio.NewScanner(f)
  31. for input.Scan() {
  32. counts[input.Text()]++
  33. }
  34. f.Close()
  35. ///////////////////////////////////////////////////////////
  36. pairList := make([]Pair, 0, len(counts))
  37. for line := range counts {
  38. pairList = append(pairList, Pair{line, counts[line]})
  39. }
  40. sort.SliceStable(pairList, func(i, j int) bool { return pairList[i].Value < pairList[j].Value })
  41. for _, pairs := range pairList {
  42. fmt.Printf("%d\t%s\n", pairs.Value, pairs.Key)
  43. }
  44. }

这是txt文件的内容:

  1. // this is the dup test file, contents are from the feel the light lyrics
  2. "Feel The Light"
  3. (from "Home" soundtrack)
  4. Hmm, hmm
  5. Hmm
  6. Here I go, here I go
  7. Feel better now, feel better now
  8. Here I go, here I go
  9. It's better now,
  10. <details>
  11. <summary>英文:</summary>
  12. I use sort.SliceStable for a map[string]int which read form a txt file, but after sort the results are different. I have tried translate the map to struct or slices but ethier wored, is it normally for the results?
  13. code:
  14. &lt;!-- begin snippet: js hide: false console: true babel: false --&gt;
  15. &lt;!-- language: lang-html --&gt;
  16. func TestStableUseSlice() {
  17. counts := make(map[string]int)
  18. f, err := os.Open(&quot;/Users/boroughfan/GitDocuments/GoLangPractise/ch01/dup/text_feel_the_light_lyrics.txt&quot;)
  19. if err != nil {
  20. fmt.Fprintf(os.Stderr, &quot;dup:%v\n&quot;, err)
  21. }
  22. input := bufio.NewScanner(f)
  23. for input.Scan() {
  24. counts[input.Text()]++
  25. }
  26. f.Close()
  27. ///////////////////////////////////////////////////////////
  28. linesSlice := make([]string, 0, len(counts))
  29. for line := range counts {
  30. linesSlice = append(linesSlice, line)
  31. }
  32. sort.SliceStable(linesSlice, func(i, j int) bool {
  33. return counts[linesSlice[i]] &lt; counts[linesSlice[j]]
  34. })
  35. for _, line := range linesSlice {
  36. fmt.Printf(&quot;%d\t%s\n&quot;, counts
    , line)
  37. }
  38. }
  39. func TestStableUsePair() {
  40. counts := make(map[string]int)
  41. f, err := os.Open(&quot;/Users/boroughfan/GitDocuments/GoLangPractise/ch01/dup/text_feel_the_light_lyrics.txt&quot;)
  42. if err != nil {
  43. fmt.Fprintf(os.Stderr, &quot;dup:%v\n&quot;, err)
  44. }
  45. input := bufio.NewScanner(f)
  46. for input.Scan() {
  47. counts[input.Text()]++
  48. }
  49. f.Close()
  50. ///////////////////////////////////////////////////////////
  51. pairList := make([]Pair, 0, len(counts))
  52. for line := range counts {
  53. pairList = append(pairList, Pair{line, counts
    })
  54. }
  55. sort.SliceStable(pairList, func(i, j int) bool { return pairList[i].Value &lt; pairList[j].Value })
  56. for _, pairs := range pairList {
  57. fmt.Printf(&quot;%d\t%s\n&quot;, pairs.Value, pairs.Key)
  58. }
  59. }
  60. &lt;!-- end snippet --&gt;
  61. here is the txt file:
  62. ```txt
  63. // this is the dup test file, contents are from the feel the light lyrics
  64. &quot;Feel The Light&quot;
  65. (from &quot;Home&quot; soundtrack)
  66. Hmm, hmm
  67. Hmm
  68. Here I go, here I go
  69. Feel better now, feel better now
  70. Here I go, here I go
  71. It&#39;s better now, feel better now
  72. Do you remember when we fell under
  73. Did you expect me to reason with thunder
  74. I still remember when time was frozen
  75. What seemed forever was just a moment
  76. Hurry up, hurry up
  77. There&#39;s no more waiting
  78. We&#39;re still worth saving
  79. Feel the light
  80. Shining in the dark of night
  81. Remember what we forgot
  82. I know it&#39;s a long shot
  83. But we&#39;re bringing it all back
  84. We&#39;re bringing it all back
  85. Feel the light
  86. Shining like the stars tonight
  87. Remember what we forgot
  88. I know it&#39;s a long shot
  89. But we&#39;re bringing it all back
  90. We&#39;re bringing it all back
  91. Here I go, here I go
  92. Feel better now, feel better now
  93. Here I go, here I go
  94. It&#39;s better now, feel better now
  95. I still remember when things were broken
  96. But put together the cracks we&#39;ll close in
  97. Hurry up, hurry up
  98. There&#39;s no more waiting
  99. We&#39;re still worth saving
  100. Feel the light
  101. Shining in the dark of night
  102. Remember what we forgot
  103. I know it&#39;s a long shot
  104. But we&#39;re bringing it all back
  105. We&#39;re bringing it all back
  106. Feel the light
  107. Shining like the stars tonight
  108. Remember what we forgot
  109. I know it&#39;s a long shot
  110. But we&#39;re bringing it all back
  111. We&#39;re bringing it all back
  112. You and I can have it all tonight
  113. So let&#39;s bring it back to life
  114. Now we have another chance to fly
  115. Another chance to make it right
  116. Feel the light
  117. Shining in the dark of night
  118. Remember what we forgot
  119. I know it&#39;s a long shot
  120. Feel the light
  121. Shining like the stars tonight
  122. Remember what we forgot
  123. I know it&#39;s a long shot
  124. But we&#39;re bringing it all back
  125. We&#39;re bringing it all back
  126. Here we go, here we go
  127. Feel better now, feel better now
  128. Here we go, here we go
  129. It&#39;s better now, feel better now

答案1

得分: -1

  1. 对于 counts 中的每一行:
  2. ...

将按照映射给出的随机顺序枚举存储在 counts 映射中的行。

sort.SliceStable() 的 "stable" 部分不会使具有相同出现次数的两行变得无序,相反,它将保留这些行的初始顺序。


例如:

"Here we go, here we go""We're still worth saving" 都有出现次数为 2,所以:

如果 "Here we go, here we go" 在初始切片中出现在 "We're still worth saving" 之前(或之后),在调用 sort.SliceStable() 后,它仍然会在结果切片中保持在之前(或之后)。


如果你想要一个一致的顺序,可以选择一种完全排序行之间的方式:

  1. sort.SliceStable(linesSlice, func(i, j int) bool {
  2. if counts[linesSlice[i]] != counts[linesSlice[j]] {
  3. return counts[linesSlice[i]] < counts[linesSlice[j]]
  4. }
  5. // 在这个例子中:如果行具有相同的计数,按字母顺序排序它们:
  6. return linesSlice[i] < linesSlice[j]
  7. })

(注意,如果元素之间的顺序是完全的,就不再需要 Stable 了)

英文:
  1. for line := range counts {
  2. ...

will enumerate the lines stored in the counts map following the randomized order given by the map.

The "stable" part of sort.SliceStable() will not un-randomize two lines which have the same occurrence count in your text -- quite the contrary: it will preserve the initial order of such lines.


For example :

&quot;Here we go, here we go&quot; and &quot;We&#39;re still worth saving&quot; both have count 2, so :

if &quot;Here we go, here we go&quot; appears before (resp. after) &quot;We&#39;re still worth saving&quot; in your initial slice, it will remain before (resp. after) in the resulting slice after calling sort.SliceStable().


If you want a consistent order, choose a way to completely order the lines between them :

  1. sort.SliceStable(linesSlice, func(i, j int) bool {
  2. if counts[linesSlice[i]] != counts[linesSlice[j]] {
  3. return counts[linesSlice[i]] &lt; counts[linesSlice[j]]
  4. }
  5. // in this example: if lines have same count, order them alphabetically:
  6. return linesSlice[i] &lt; linesSlice[j]
  7. })

(note that if the order between elements is complete, you don't need the Stable anymore)

huangapple
  • 本文由 发表于 2022年8月1日 22:29:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/73195260.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定