这是我想要的结果
slice1 := []string{"foo", "bar","hello"}
slice2 := []string{"foo", "bar"}
difference(slice1, slice2)
=> ["hello"]
我正在寻找两个字符串切片之间的区别!
答案 0 :(得分:24)
假设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
}
答案 1 :(得分:14)
根据切片的大小,不同的解决方案可能是最好的。
我的回答假设顺序无关紧要。
使用简单循环,仅用于较小的切片:
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))
}
输出:
[hello world]
答案 2 :(得分:12)
我使用地图来解决这个问题
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
}
输出:
你好
世界
答案 3 :(得分:1)
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]
}
答案 4 :(得分:0)
作为mentioned by ANisus,不同的方法适合不同大小的输入切片。此解决方案将在与输入大小无关的线性时间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))
}
产地:
=&GT;喂
如果您将切片更改为:
func main() {
slice1 := []string{"foo", "baz", "hello"}
slice2 := []string{"foo", "bar"}
fmt.Print(difference(slice1, slice2))
}
它会产生:
=&GT;巴兹吧
=&GT;喂
答案 5 :(得分:0)
如果切片包含重复的元素,此处的大多数其他解决方案将无法返回正确的答案。
如果切片已排序,则此解决方案为O(n)时间和O(n)空间;如果未排序,则为O(n * log(n))时间O(n)空间,但具有不错的属性实际上是正确的。
jlink \
--add-modules java.base,java.logging,java.xml,jdk.unsupported,java.sql,java.naming,java.desktop,java.management,java.security.jgss,java.instrument,jdk.management,java.net.http \
--module-path $(find $JAVA_HOME -name lib -type d) \
--output ~/jre
如果您确定已对切片进行了排序,则可以删除对func diff(a, b []string) []string {
a = sortIfNeeded(a)
b = sortIfNeeded(b)
var d []string
i, j := 0, 0
for i < len(a) && j < len(b) {
c := strings.Compare(a[i], b[j])
if c == 0 {
i++
j++
} else if c < 0 {
d = append(d, a[i])
i++
} else {
d = append(d, b[j])
j++
}
}
d = append(d, a[i:len(a)]...)
d = append(d, b[j:len(b)]...)
return d
}
func sortIfNeeded(a []string) []string {
if sort.StringsAreSorted(a) {
return a
}
s := append(a[:0:0], a...)
sort.Strings(s)
return s
}
的调用(sortIfNeeded
中具有防御性的切片副本的原因是,排序是就地完成的,因此我们将修改传递到sortIfNeeded
的切片。
有关面对重复条目的正确性的测试,请参见https://play.golang.org/p/lH-5L0aL1qr。
答案 6 :(得分:0)
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)
(v<0
)
答案 7 :(得分:0)
这是我的解决方案,使用package sort
first
中找到不在second
中的元素:second
中first
的{{3}}或first
\ { {1}}。second
进行了分类!对于某些用例,这可能是个问题。second
答案 8 :(得分:-1)
下面的代码给出了字符串之间的绝对差异,而与顺序无关。空间复杂度O(n)和时间复杂度O(n)。
// 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)
}