英文:
Iterate over 2 strings in go
问题
我想逐个比较两个字符串的符文,以确定它们在任意字母顺序中的先后顺序。
目前我有这个实现,它在map[rune]int
中存储了表示字母顺序的映射。
我有这个可工作的代码。我很清楚当前设计中的缺陷,但这不是问题的重点。
package main
import (
"bufio"
"log"
"math/rand"
"os"
"sort"
)
type Dictionnary struct {
content []string
alphaBeticalOrder map[rune]int
}
func minSize(w1, w2 []rune) int {
if len(w1) < len(w2) {
return len(w1)
}
return len(w2)
}
func (d *Dictionnary) comesFirst(a, b rune) int {
return d.alphaBeticalOrder[a] - d.alphaBeticalOrder[b]
}
func (d Dictionnary) Less(i, j int) bool {
wordi, wordj := []rune(d.content[i]), []rune(d.content[j])
size := minSize(wordi, wordj)
for index := 0; index < size; index++ {
diff := d.comesFirst(wordi[index], wordj[index])
switch {
case diff < 0:
return true
case diff > 0:
return false
default:
continue
}
}
return len(wordi) < len(wordj)
}
func (d Dictionnary) Swap(i, j int) {
d.content[i], d.content[j] = d.content[j], d.content[i]
}
func (d Dictionnary) Len() int {
return len(d.content)
}
func main() {
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'}
aOrder := make(map[rune]int)
perm := rand.Perm(len(letters))
for i, v := range perm {
aOrder[letters[i]] = v
}
file, err := os.Open("testdata/corpus.txt")
if err != nil {
log.Fatal(err)
}
corpus := make([]string, 0, 1000)
scanner := bufio.NewScanner(file)
for scanner.Scan() {
corpus = append(corpus, scanner.Text())
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
file.Close()
input := Dictionnary{content: corpus, alphaBeticalOrder: aOrder}
sort.Sort(input)
ofile, err := os.Create("testdata/sorted.txt")
writer := bufio.NewWriter(ofile)
for _, v := range input.content {
writer.WriteString(v)
writer.WriteString("\n")
}
writer.Flush()
defer ofile.Close()
}
我的问题涉及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.
package main
import (
"bufio"
"log"
"math/rand"
"os"
"sort"
)
type Dictionnary struct {
content []string
alphaBeticalOrder map[rune]int
}
func minSize(w1, w2 []rune) int {
if len(w1) < len(w2) {
return len(w1)
}
return len(w2)
}
func (d *Dictionnary) comesFirst(a, b rune) int {
return d.alphaBeticalOrder[a] - d.alphaBeticalOrder[b]
}
func (d Dictionnary) Less(i, j int) bool {
wordi, wordj := []rune(d.content[i]), []rune(d.content[j])
size := minSize(wordi, wordj)
for index := 0; index < size; index++ {
diff := d.comesFirst(wordi[index], wordj[index])
switch {
case diff < 0:
return true
case diff > 0:
return false
default:
continue
}
}
return len(wordi) < len(wordj)
}
func (d Dictionnary) Swap(i, j int) {
d.content[i], d.content[j] = d.content[j], d.content[i]
}
func (d Dictionnary) Len() int {
return len(d.content)
}
func main() {
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'}
aOrder := make(map[rune]int)
perm := rand.Perm(len(letters))
for i, v := range perm {
aOrder[letters[i]] = v
}
file, err := os.Open("testdata/corpus.txt")
if err != nil {
log.Fatal(err)
}
corpus := make([]string, 0, 1000)
scanner := bufio.NewScanner(file)
for scanner.Scan() {
corpus = append(corpus, scanner.Text())
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
file.Close()
input := Dictionnary{content: corpus, alphaBeticalOrder: aOrder}
sort.Sort(input)
ofile, err := os.Create("testdata/sorted.txt")
writer := bufio.NewWriter(ofile)
for _, v := range input.content {
writer.WriteString(v)
writer.WriteString("\n")
}
writer.Flush()
defer ofile.Close()
}
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
}
diff := d.comesFirst(c, wordj[i])
switch {
case diff < 0:
return true
case diff > 0:
return false
default:
continue
}
}
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.
// determines if the word indexed at i is less than the word indexed at 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
}
diff := d.comesFirst(c, wordj[i])
switch {
case diff < 0:
return true
case diff > 0:
return false
default:
continue
}
}
return false
}
答案2
得分: 1
在Less
方法中迭代两个字符串并进行比较:
package main
import (
"bufio"
"log"
"math/rand"
"os"
"sort"
"unicode/utf8"
)
type Dictionary struct {
content []string
alphaBeticalOrder map[rune]int
}
func (d Dictionary) Len() int {
return len(d.content)
}
func (d Dictionary) Swap(i, j int) {
d.content[i], d.content[j] = d.content[j], d.content[i]
}
func (d Dictionary) Less(i, j int) bool {
wi, wj := d.content[i], d.content[j]
jj := 0
for _, ri := range wi {
rj, size := utf8.DecodeRuneInString(wj[jj:])
if rj == utf8.RuneError && size == 0 {
return false
}
switch ao := d.alphaBeticalOrder[ri] - d.alphaBeticalOrder[rj]; {
case ao < 0:
return true
case ao > 0:
return false
}
jj += size
}
return len(wi) < len(wj)
}
func main() {
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'}
aOrder := make(map[rune]int)
perm := rand.Perm(len(letters))
for i, v := range perm {
aOrder[letters[i]] = v
}
file, err := os.Open("testdata/corpus.txt")
if err != nil {
log.Fatal(err)
}
corpus := make([]string, 0, 1000)
scanner := bufio.NewScanner(file)
for scanner.Scan() {
corpus = append(corpus, scanner.Text())
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
file.Close()
input := Dictionary{content: corpus, alphaBeticalOrder: aOrder}
sort.Sort(input)
ofile, err := os.Create("testdata/sorted.txt")
writer := bufio.NewWriter(ofile)
for _, v := range input.content {
writer.WriteString(v)
writer.WriteString("\n")
}
writer.Flush()
defer ofile.Close()
}
以上是迭代两个字符串并在Less
方法中进行比较的代码。
英文:
To iterate over two strings side-by-side in the Less
method:
package main
import (
"bufio"
"log"
"math/rand"
"os"
"sort"
"unicode/utf8"
)
type Dictionary struct {
content []string
alphaBeticalOrder map[rune]int
}
func (d Dictionary) Len() int {
return len(d.content)
}
func (d Dictionary) Swap(i, j int) {
d.content[i], d.content[j] = d.content[j], d.content[i]
}
func (d Dictionary) Less(i, j int) bool {
wi, wj := d.content[i], d.content[j]
jj := 0
for _, ri := range wi {
rj, size := utf8.DecodeRuneInString(wj[jj:])
if rj == utf8.RuneError && size == 0 {
return false
}
switch ao := d.alphaBeticalOrder[ri] - d.alphaBeticalOrder[rj]; {
case ao < 0:
return true
case ao > 0:
return false
}
jj += size
}
return len(wi) < len(wj)
}
func main() {
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'}
aOrder := make(map[rune]int)
perm := rand.Perm(len(letters))
for i, v := range perm {
aOrder[letters[i]] = v
}
file, err := os.Open("testdata/corpus.txt")
if err != nil {
log.Fatal(err)
}
corpus := make([]string, 0, 1000)
scanner := bufio.NewScanner(file)
for scanner.Scan() {
corpus = append(corpus, scanner.Text())
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
file.Close()
input := Dictionary{content: corpus, alphaBeticalOrder: aOrder}
sort.Sort(input)
ofile, err := os.Create("testdata/sorted.txt")
writer := bufio.NewWriter(ofile)
for _, v := range input.content {
writer.WriteString(v)
writer.WriteString("\n")
}
writer.Flush()
defer ofile.Close()
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论