Go 如何找出两段字符串之间的差异

Go 如何找出两段字符串之间的差异,go,Go,这是我想要的结果 slice1 := []string{"foo", "bar","hello"} slice2 := []string{"foo", "bar"} difference(slice1, slice2) => ["hello"] 我正在寻找两个字符串片段之间的差异 As,不同的方法将适合不同大小的输入切片。此解决方案将在线性时间O(n)中工作,与输入大小无关,但假设“相等”包括索引位置 因此,在OP的示例中: slice1 := []string{"foo", "bar

这是我想要的结果

slice1 := []string{"foo", "bar","hello"}
slice2 := []string{"foo", "bar"}

difference(slice1, slice2)
=> ["hello"]
我正在寻找两个字符串片段之间的差异

As,不同的方法将适合不同大小的输入切片。此解决方案将在线性时间
O(n)
中工作,与输入大小无关,但假设“相等”包括索引位置

因此,在OP的示例中:

slice1 := []string{"foo", "bar","hello"}
slice2 := []string{"foo", "bar"}
条目
foo
bar
不仅因为值,而且因为它们在切片中的索引而相等

在这些条件下,您可以执行以下操作:

package main

import "fmt"

func difference(s1, s2 []string) string {
    var (
        lenMin  int
        longest []string
        out     string
    )
    // Determine the shortest length and the longest slice
    if len(s1) < len(s2) {
        lenMin = len(s1)
        longest = s2
    } else {
        lenMin = len(s2)
        longest = s1
    }
    // compare common indeces
    for i := 0; i < lenMin; i++ {
        if s1[i] != s2[i] {
            out += fmt.Sprintf("=>\t%s\t%s\n", s1[i], s2[i])
        }
    }
    // add indeces not in common
    for _, v := range longest[lenMin:] {
        out += fmt.Sprintf("=>\t%s\n", v)
    }
    return out
}

func main() {
    slice1 := []string{"foo", "bar", "hello"}
    slice2 := []string{"foo", "bar"}
    fmt.Print(difference(slice1, slice2))
}
它将产生:

=>baz条
=>你好


根据切片的大小,不同的解决方案可能是最好的

我的回答是假设秩序无关紧要

使用简单循环,仅用于较小的切片:

package main

import "fmt"

func difference(slice1 []string, slice2 []string) []string {
    var diff []string

    // Loop two times, first to find slice1 strings not in slice2,
    // second loop to find slice2 strings not in slice1
    for i := 0; i < 2; i++ {
        for _, s1 := range slice1 {
            found := false
            for _, s2 := range slice2 {
                if s1 == s2 {
                    found = true
                    break
                }
            }
            // String not found. We add it to return slice
            if !found {
                diff = append(diff, s1)
            }
        }
        // Swap the slices, only if it was the first loop
        if i == 0 {
            slice1, slice2 = slice2, slice1
        }
    }

    return diff
}

func main() {
    slice1 := []string{"foo", "bar", "hello"}
    slice2 := []string{"foo", "world", "bar", "foo"}

    fmt.Printf("%+v\n", difference(slice1, slice2))
}

操场:

我用地图解决这个问题

package main

import "fmt"

func main() {
    slice1 := []string{"foo", "bar","hello"}
    slice2 := []string{"foo", "bar","world"}

    diffStr := difference(slice1, slice2)

    for _, diffVal := range diffStr {
        fmt.Println(diffVal)
    }

}

func difference(slice1 []string, slice2 []string) ([]string){
    diffStr := []string{}
    m :=map [string]int{}

    for _, s1Val := range slice1 {
        m[s1Val] = 1
    }
    for _, s2Val := range slice2 {
        m[s2Val] = m[s2Val] + 1
    }

    for mKey, mVal := range m {
        if mVal==1 {
            diffStr = append(diffStr, mKey)
        }
    }

    return diffStr
}
输出:
你好
world

假设Go贴图是~O(1),这里有一个~O(n)差分函数,它适用于未排序的切片

// difference returns the elements in `a` that aren't in `b`.
func difference(a, b []string) []string {
    mb := make(map[string]struct{}, len(b))
    for _, x := range b {
        mb[x] = struct{}{}
    }
    var diff []string
    for _, x := range a {
        if _, found := mb[x]; !found {
            diff = append(diff, x)
        }
    }
    return diff
}

下面的代码给出了字符串之间的绝对差异,而与顺序无关。空间复杂度O(n)和时间复杂度O(n)


如果切片包含重复的元素,这里的大多数其他解决方案将无法返回正确答案。

如果切片已排序,则此解为O(n)时间和O(n)空间;如果切片未排序,则为O(n*log(n))时间和O(n)空间,但具有实际正确的特性。
func diff(a, b []string) []string {
    temp := map[string]int{}
    for _, s := range a {
        temp[s]++
    }
    for _, s := range b {
        temp[s]--
    }

    var result []string
    for s, v := range temp {
        if v != 0 {
            result = append(result, s)
        }
    }
    return result
}


如果要处理重复的字符串,则映射中的
v
可以执行此操作。您可以选择
a.Remove(b)
v>0
)或
b.Remove(a)
vCan我们可以假设字符串的顺序无关紧要吗?@ANisus我假设我必须将每个索引与等效索引进行比较。否则就需要对切片进行排序,或者对每个切片成员与另一个切片的每个成员进行非常慢的比较。希望这就是所需的一切!@Intermernet是的,我的答案是正确的顺序索引位置并不重要。当然,我的只是一个简单且“愚蠢”的循环,时间为O(n*m)。对于较大的循环,也许某种排序或映射解决方案更好。但是:
slice1:=[]字符串{“foo”,“bar”,“hello”}
slice2:=[]字符串{“foox”,“foo”,“bar”}
?程序输出
foo
bar
,这两个部分都有。@topskip Intermernet假定OP希望将每个索引与等效索引进行比较。OP在考虑顺序和索引值的情况下,不太清楚他希望进行哪种比较。@ANisus你说得对,我错过了这一点。我想我会比较一下不过,请留下我的评论,以便将来的用户知道这个问题。@topskip,是的,我假设OP想要逐个索引进行比较。ANisus提供的解决方案可能就是OP所追求的,尽管我想不出一种在处理大切片时不降低性能的方法。我只是注意到如果你这样做的话类似于
slice1:=[]字符串{“foo”}切片2:=[]字符串{“foo”,“foo”}
你不会有任何区别。我希望我们在构成“差异”的更精细点上有更多的指导!是数据+索引,只是数据,还是唯一数据?无论如何,答案很好。@Intermernet在我的示例中,我故意添加了两个“foo”“在第二部分中,只是为了明确函数在这种情况下的行为。但是,是的,我们的两个答案都是正确的,这取决于OP如何定义“差异”.是的,我注意到,这正是引发我思考的原因,我很高兴你能在示例中说明这一事实。有趣的是,这样一个看似简单的问题包含了如此多的警告:-)也许我们会从OP中得到一些说明!注意,这个解决方案是1)如果slice1和slice2有许多元素,效率极低;2)如另一条注释中所述,如果切片可以包含重复的元素,则效率不正确这是比上述所有答案更好的解决方案这很好,但是
ab:=[]字符串{}
应该是
var ab[]string
如果切片包含重复的元素,此解决方案将崩溃。我认为问题在于设置的go切片。对于多集,这段代码有一个明显的变体:将mb设为map[string]int,并在找到x时从mb[x]中减去1。假设len(a)=n,len(b)=m,这个解决方案不应该是O(n)+n*log(m)?这并不适用于所有情况。。。切片1:=[]字符串{};slice2:=[]字符串{“duplicate”,“duplicate”}stringBuilder始终建议用于构建字符串,因为字符串在golang中是不可变的。问题是关于
[]字符串
的差异;此解决方案与
字符串的差异有关。此外,该解决方案是不正确的,因为它也不处理重复的符文。
// difference returns the elements in `a` that aren't in `b`.
func difference(a, b []string) []string {
    mb := make(map[string]struct{}, len(b))
    for _, x := range b {
        mb[x] = struct{}{}
    }
    var diff []string
    for _, x := range a {
        if _, found := mb[x]; !found {
            diff = append(diff, x)
        }
    }
    return diff
}
func unique(slice []string) []string {
    encountered := map[string]int{}
    diff := []string{}

    for _, v := range slice {
        encountered[v] = encountered[v]+1
    }

    for _, v := range slice {
        if encountered[v] == 1 {
        diff = append(diff, v)
        }
    }
    return diff
}

func main() {
    slice1 := []string{"hello", "michael", "dorner"}
    slice2 := []string{"hello", "michael"}
    slice3 := []string{}
    fmt.Println(unique(append(slice1, slice2...))) // [dorner]
    fmt.Println(unique(append(slice2, slice3...))) // [michael michael]
}
// difference returns the elements in a that aren't in b
func difference(a, b string) string {
    longest, shortest := longestString(&a, &b)
    var builder strings.Builder
    var mem = make(map[rune]bool)
    for _, s := range longest {
        mem[s] = true
    }
    for _, s := range shortest {
        if _, ok := mem[s]; ok {
            mem[s] = false
        }
    }
    for k, v := range mem {
        if v == true {
            builder.WriteRune(k)
        }
    }
    return builder.String()
}
func longestString(a *string, b *string) ([]rune, []rune) {
    if len(*a) > len(*b) {
        return []rune(*a), []rune(*b)
    }
    return []rune(*b), []rune(*a)
}
func diff(a, b []string) []string {
    temp := map[string]int{}
    for _, s := range a {
        temp[s]++
    }
    for _, s := range b {
        temp[s]--
    }

    var result []string
    for s, v := range temp {
        if v != 0 {
            result = append(result, s)
        }
    }
    return result
}