douzhuo3233 2014-10-15 15:29
浏览 61
已采纳

遍历2个字符串

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("
")
    }
    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.

  • 写回答

2条回答 默认 最新

  • dousi8237 2014-10-16 03:26
    关注

    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("
    ")
        }
        writer.Flush()
        defer ofile.Close()
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 对于相关问题的求解与代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 信号傅里叶变换在matlab上遇到的小问题请求帮助
  • ¥15 保护模式-系统加载-段寄存器
  • ¥15 电脑桌面设定一个区域禁止鼠标操作
  • ¥15 求NPF226060磁芯的详细资料