Iterate over 2 strings in go

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

Iterate over 2 strings in go

问题

我想逐个比较两个字符串的符文,以确定它们在任意字母顺序中的先后顺序。

目前我有这个实现,它在map[rune]int中存储了表示字母顺序的映射。

我有这个可工作的代码。我很清楚当前设计中的缺陷,但这不是问题的重点。

  1. package main
  2. import (
  3. "bufio"
  4. "log"
  5. "math/rand"
  6. "os"
  7. "sort"
  8. )
  9. type Dictionnary struct {
  10. content []string
  11. alphaBeticalOrder map[rune]int
  12. }
  13. func minSize(w1, w2 []rune) int {
  14. if len(w1) < len(w2) {
  15. return len(w1)
  16. }
  17. return len(w2)
  18. }
  19. func (d *Dictionnary) comesFirst(a, b rune) int {
  20. return d.alphaBeticalOrder[a] - d.alphaBeticalOrder[b]
  21. }
  22. func (d Dictionnary) Less(i, j int) bool {
  23. wordi, wordj := []rune(d.content[i]), []rune(d.content[j])
  24. size := minSize(wordi, wordj)
  25. for index := 0; index < size; index++ {
  26. diff := d.comesFirst(wordi[index], wordj[index])
  27. switch {
  28. case diff < 0:
  29. return true
  30. case diff > 0:
  31. return false
  32. default:
  33. continue
  34. }
  35. }
  36. return len(wordi) < len(wordj)
  37. }
  38. func (d Dictionnary) Swap(i, j int) {
  39. d.content[i], d.content[j] = d.content[j], d.content[i]
  40. }
  41. func (d Dictionnary) Len() int {
  42. return len(d.content)
  43. }
  44. func main() {
  45. letters := []rune{'z', 'y', 'x', 'w', 'v', 'u', 't', 's', 'r', 'q', 'p', 'o', 'n', 'm', 'l', 'k', 'j', 'i', 'h', 'g', 'f', 'e', 'd', 'c', 'b', 'a'}
  46. aOrder := make(map[rune]int)
  47. perm := rand.Perm(len(letters))
  48. for i, v := range perm {
  49. aOrder[letters[i]] = v
  50. }
  51. file, err := os.Open("testdata/corpus.txt")
  52. if err != nil {
  53. log.Fatal(err)
  54. }
  55. corpus := make([]string, 0, 1000)
  56. scanner := bufio.NewScanner(file)
  57. for scanner.Scan() {
  58. corpus = append(corpus, scanner.Text())
  59. }
  60. if err := scanner.Err(); err != nil {
  61. log.Fatal(err)
  62. }
  63. file.Close()
  64. input := Dictionnary{content: corpus, alphaBeticalOrder: aOrder}
  65. sort.Sort(input)
  66. ofile, err := os.Create("testdata/sorted.txt")
  67. writer := bufio.NewWriter(ofile)
  68. for _, v := range input.content {
  69. writer.WriteString(v)
  70. writer.WriteString("\n")
  71. }
  72. writer.Flush()
  73. defer ofile.Close()
  74. }

我的问题涉及Less(i, j int) bool函数。有没有更符合惯用法的方法来迭代两个字符串,以逐个比较它们的符文?我在这里复制了数据,这可能是可以避免的。

编辑:
为了澄清我的问题,range(string)可以让您逐个迭代字符串的符文,但我无法找到一种同时迭代两个字符串的方法。我唯一能想到的方法是将字符串转换为[]rune

英文:

I want to compare 2 strings rune-by-rune to see which one comes first in an arbitrary alphabetical order.

Right now I have this implementation which stores in map[rune]int a mapping representing the order of letters in my alphabet.

I have this working code. I'm well aware of the flaws in the current design, but this isn't the point of the question.

  1. package main
  2. import (
  3. &quot;bufio&quot;
  4. &quot;log&quot;
  5. &quot;math/rand&quot;
  6. &quot;os&quot;
  7. &quot;sort&quot;
  8. )
  9. type Dictionnary struct {
  10. content []string
  11. alphaBeticalOrder map[rune]int
  12. }
  13. func minSize(w1, w2 []rune) int {
  14. if len(w1) &lt; len(w2) {
  15. return len(w1)
  16. }
  17. return len(w2)
  18. }
  19. func (d *Dictionnary) comesFirst(a, b rune) int {
  20. return d.alphaBeticalOrder[a] - d.alphaBeticalOrder[b]
  21. }
  22. func (d Dictionnary) Less(i, j int) bool {
  23. wordi, wordj := []rune(d.content[i]), []rune(d.content[j])
  24. size := minSize(wordi, wordj)
  25. for index := 0; index &lt; size; index++ {
  26. diff := d.comesFirst(wordi[index], wordj[index])
  27. switch {
  28. case diff &lt; 0:
  29. return true
  30. case diff &gt; 0:
  31. return false
  32. default:
  33. continue
  34. }
  35. }
  36. return len(wordi) &lt; len(wordj)
  37. }
  38. func (d Dictionnary) Swap(i, j int) {
  39. d.content[i], d.content[j] = d.content[j], d.content[i]
  40. }
  41. func (d Dictionnary) Len() int {
  42. return len(d.content)
  43. }
  44. func main() {
  45. letters := []rune{&#39;z&#39;, &#39;y&#39;, &#39;x&#39;, &#39;w&#39;, &#39;v&#39;, &#39;u&#39;, &#39;t&#39;, &#39;s&#39;, &#39;r&#39;, &#39;q&#39;, &#39;p&#39;, &#39;o&#39;, &#39;n&#39;, &#39;m&#39;, &#39;l&#39;, &#39;k&#39;, &#39;j&#39;, &#39;i&#39;, &#39;h&#39;, &#39;g&#39;, &#39;f&#39;, &#39;e&#39;, &#39;d&#39;, &#39;c&#39;, &#39;b&#39;, &#39;a&#39;}
  46. aOrder := make(map[rune]int)
  47. perm := rand.Perm(len(letters))
  48. for i, v := range perm {
  49. aOrder[letters[i]] = v
  50. }
  51. file, err := os.Open(&quot;testdata/corpus.txt&quot;)
  52. if err != nil {
  53. log.Fatal(err)
  54. }
  55. corpus := make([]string, 0, 1000)
  56. scanner := bufio.NewScanner(file)
  57. for scanner.Scan() {
  58. corpus = append(corpus, scanner.Text())
  59. }
  60. if err := scanner.Err(); err != nil {
  61. log.Fatal(err)
  62. }
  63. file.Close()
  64. input := Dictionnary{content: corpus, alphaBeticalOrder: aOrder}
  65. sort.Sort(input)
  66. ofile, err := os.Create(&quot;testdata/sorted.txt&quot;)
  67. writer := bufio.NewWriter(ofile)
  68. for _, v := range input.content {
  69. writer.WriteString(v)
  70. writer.WriteString(&quot;\n&quot;)
  71. }
  72. writer.Flush()
  73. defer ofile.Close()
  74. }

My question concerns the Less(i,j int) bool function. Is there a more idiomatic way to iterate over 2 strings to compare them rune by rune ? I am making a copy of data here which could probably be avoided.

EDIT:
To clarify my problem is that range(string) can allow you to iterate over strings rune by rune, but I cannot see a way to iterate over 2 strings side-by-side. Only way I see it to convert the strings to []rune.

答案1

得分: 2

你可以使用其中一个单词的范围来使循环更加惯用化。
这需要在循环内部添加一个检查,但你不再需要在最后的返回处执行检查。

// 确定索引为i的单词是否小于索引为j的单词。
func (d Dictionnary) Less(i, j int) bool {
wordi, wordj := []rune(d.content[i]), []rune(d.content[j])
for i, c := range wordi {
if i == len(wordj) {
return false
}

  1. diff := d.comesFirst(c, wordj[i])
  2. switch {
  3. case diff < 0:
  4. return true
  5. case diff > 0:
  6. return false
  7. default:
  8. continue
  9. }
  10. }
  11. return false

}

英文:

You could make the loop slightly more idiomatic using a range on one of the two words.
This necessitates adding a check within the loop but you no longer have to perform the check at the final return.

  1. // determines if the word indexed at i is less than the word indexed at j.
  2. func (d Dictionnary) Less(i, j int) bool {
  3. wordi, wordj := []rune(d.content[i]), []rune(d.content[j])
  4. for i, c := range wordi {
  5. if i == len(wordj) {
  6. return false
  7. }
  8. diff := d.comesFirst(c, wordj[i])
  9. switch {
  10. case diff &lt; 0:
  11. return true
  12. case diff &gt; 0:
  13. return false
  14. default:
  15. continue
  16. }
  17. }
  18. return false
  19. }

答案2

得分: 1

Less方法中迭代两个字符串并进行比较:

  1. package main
  2. import (
  3. "bufio"
  4. "log"
  5. "math/rand"
  6. "os"
  7. "sort"
  8. "unicode/utf8"
  9. )
  10. type Dictionary struct {
  11. content []string
  12. alphaBeticalOrder map[rune]int
  13. }
  14. func (d Dictionary) Len() int {
  15. return len(d.content)
  16. }
  17. func (d Dictionary) Swap(i, j int) {
  18. d.content[i], d.content[j] = d.content[j], d.content[i]
  19. }
  20. func (d Dictionary) Less(i, j int) bool {
  21. wi, wj := d.content[i], d.content[j]
  22. jj := 0
  23. for _, ri := range wi {
  24. rj, size := utf8.DecodeRuneInString(wj[jj:])
  25. if rj == utf8.RuneError && size == 0 {
  26. return false
  27. }
  28. switch ao := d.alphaBeticalOrder[ri] - d.alphaBeticalOrder[rj]; {
  29. case ao < 0:
  30. return true
  31. case ao > 0:
  32. return false
  33. }
  34. jj += size
  35. }
  36. return len(wi) < len(wj)
  37. }
  38. func main() {
  39. letters := []rune{'z', 'y', 'x', 'w', 'v', 'u', 't', 's', 'r', 'q', 'p', 'o', 'n', 'm', 'l', 'k', 'j', 'i', 'h', 'g', 'f', 'e', 'd', 'c', 'b', 'a'}
  40. aOrder := make(map[rune]int)
  41. perm := rand.Perm(len(letters))
  42. for i, v := range perm {
  43. aOrder[letters[i]] = v
  44. }
  45. file, err := os.Open("testdata/corpus.txt")
  46. if err != nil {
  47. log.Fatal(err)
  48. }
  49. corpus := make([]string, 0, 1000)
  50. scanner := bufio.NewScanner(file)
  51. for scanner.Scan() {
  52. corpus = append(corpus, scanner.Text())
  53. }
  54. if err := scanner.Err(); err != nil {
  55. log.Fatal(err)
  56. }
  57. file.Close()
  58. input := Dictionary{content: corpus, alphaBeticalOrder: aOrder}
  59. sort.Sort(input)
  60. ofile, err := os.Create("testdata/sorted.txt")
  61. writer := bufio.NewWriter(ofile)
  62. for _, v := range input.content {
  63. writer.WriteString(v)
  64. writer.WriteString("\n")
  65. }
  66. writer.Flush()
  67. defer ofile.Close()
  68. }

以上是迭代两个字符串并在Less方法中进行比较的代码。

英文:

To iterate over two strings side-by-side in the Less method:

  1. package main
  2. import (
  3. &quot;bufio&quot;
  4. &quot;log&quot;
  5. &quot;math/rand&quot;
  6. &quot;os&quot;
  7. &quot;sort&quot;
  8. &quot;unicode/utf8&quot;
  9. )
  10. type Dictionary struct {
  11. content []string
  12. alphaBeticalOrder map[rune]int
  13. }
  14. func (d Dictionary) Len() int {
  15. return len(d.content)
  16. }
  17. func (d Dictionary) Swap(i, j int) {
  18. d.content[i], d.content[j] = d.content[j], d.content[i]
  19. }
  20. func (d Dictionary) Less(i, j int) bool {
  21. wi, wj := d.content[i], d.content[j]
  22. jj := 0
  23. for _, ri := range wi {
  24. rj, size := utf8.DecodeRuneInString(wj[jj:])
  25. if rj == utf8.RuneError &amp;&amp; size == 0 {
  26. return false
  27. }
  28. switch ao := d.alphaBeticalOrder[ri] - d.alphaBeticalOrder[rj]; {
  29. case ao &lt; 0:
  30. return true
  31. case ao &gt; 0:
  32. return false
  33. }
  34. jj += size
  35. }
  36. return len(wi) &lt; len(wj)
  37. }
  38. func main() {
  39. letters := []rune{&#39;z&#39;, &#39;y&#39;, &#39;x&#39;, &#39;w&#39;, &#39;v&#39;, &#39;u&#39;, &#39;t&#39;, &#39;s&#39;, &#39;r&#39;, &#39;q&#39;, &#39;p&#39;, &#39;o&#39;, &#39;n&#39;, &#39;m&#39;, &#39;l&#39;, &#39;k&#39;, &#39;j&#39;, &#39;i&#39;, &#39;h&#39;, &#39;g&#39;, &#39;f&#39;, &#39;e&#39;, &#39;d&#39;, &#39;c&#39;, &#39;b&#39;, &#39;a&#39;}
  40. aOrder := make(map[rune]int)
  41. perm := rand.Perm(len(letters))
  42. for i, v := range perm {
  43. aOrder[letters[i]] = v
  44. }
  45. file, err := os.Open(&quot;testdata/corpus.txt&quot;)
  46. if err != nil {
  47. log.Fatal(err)
  48. }
  49. corpus := make([]string, 0, 1000)
  50. scanner := bufio.NewScanner(file)
  51. for scanner.Scan() {
  52. corpus = append(corpus, scanner.Text())
  53. }
  54. if err := scanner.Err(); err != nil {
  55. log.Fatal(err)
  56. }
  57. file.Close()
  58. input := Dictionary{content: corpus, alphaBeticalOrder: aOrder}
  59. sort.Sort(input)
  60. ofile, err := os.Create(&quot;testdata/sorted.txt&quot;)
  61. writer := bufio.NewWriter(ofile)
  62. for _, v := range input.content {
  63. writer.WriteString(v)
  64. writer.WriteString(&quot;\n&quot;)
  65. }
  66. writer.Flush()
  67. defer ofile.Close()
  68. }

huangapple
  • 本文由 发表于 2014年10月15日 23:29:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/26386346.html
匿名

发表评论

匿名网友

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

确定