[英]How to remove duplicates strings or int from Slice in Go
假設我有一個學生城市列表,它的大小可以是 100 或 1000,我想過濾掉所有重復的城市。
我想要一個通用的解決方案,可以用來從任何切片中刪除所有重復的字符串。
我是 Go 語言的新手,所以我嘗試通過循環並使用另一個循環 function 檢查元素是否存在來做到這一點。
學生城市列表(數據):
studentsCities := []string{"Mumbai", "Delhi", "Ahmedabad", "Mumbai", "Bangalore", "Delhi", "Kolkata", "Pune"}
我創建的功能,它正在做的工作:
func contains(s []string, e string) bool {
for _, a := range s {
if a == e {
return true
}
}
return false
}
func removeDuplicates(strList []string) []string {
list := []string{}
for _, item := range strList {
fmt.Println(item)
if contains(list, item) == false {
list = append(list, item)
}
}
return list
}
我的解決方案測試
func main() {
studentsCities := []string{"Mumbai", "Delhi", "Ahmedabad", "Mumbai", "Bangalore", "Delhi", "Kolkata", "Pune"}
uniqueStudentsCities := removeDuplicates(studentsCities)
fmt.Println(uniqueStudentsCities) // Expected output [Mumbai Delhi Ahmedabad Bangalore Kolkata Pune]
}
我相信我嘗試的上述解決方案不是最佳解決方案。 因此,我需要你們的幫助來建議從切片中刪除重復項的最快方法?
我檢查了 StackOverflow,這個問題還沒有被問到,所以我沒有得到任何解決方案。
我發現Burak和Fazlan 的解決方案很有幫助。 基於此,我實現了一些簡單的函數,這些函數有助於使用通用方法從字符串、整數或任何其他類型的切片中刪除或過濾重復數據。
這是我的三個函數,第一個是通用的,第二個用於字符串,最后一個用於切片整數。 您必須傳遞您的數據並返回所有唯一值作為結果。
通用解決方案: => Go v1.18
func removeDuplicate[T string | int](sliceList []T) []T {
allKeys := make(map[T]bool)
list := []T{}
for _, item := range sliceList {
if _, value := allKeys[item]; !value {
allKeys[item] = true
list = append(list, item)
}
}
return list
}
要從切片中刪除重復的字符串:
func removeDuplicateStr(strSlice []string) []string {
allKeys := make(map[string]bool)
list := []string{}
for _, item := range strSlice {
if _, value := allKeys[item]; !value {
allKeys[item] = true
list = append(list, item)
}
}
return list
}
要從切片中刪除重復的整數:
func removeDuplicateInt(intSlice []int) []int {
allKeys := make(map[int]bool)
list := []int{}
for _, item := range intSlice {
if _, value := allKeys[item]; !value {
allKeys[item] = true
list = append(list, item)
}
}
return list
}
您可以更新切片類型,它將過濾掉所有切片類型的所有重復數據。
這是 GoPlayground 鏈接: https://go.dev/play/p/iyb97KcftMa
您可以在 map 的指導下進行就地更換:
processed := map[string]struct{}{}
w := 0
for _, s := range cities {
if _, exists := processed[s]; !exists {
// If this city has not been seen yet, add it to the list
processed[s] = struct{}{}
cities[w] = s
w++
}
}
cities = cities[:w]
但是,添加這個對我有用的答案確實需要/包括排序。
func removeDuplicateStrings(s []string) []string {
if len(s) < 1 {
return s
}
sort.Strings(s)
prev := 1
for curr := 1; curr < len(s); curr++ {
if s[curr-1] != s[curr] {
s[prev] = s[curr]
prev++
}
}
return s[:prev]
}
為了好玩,我嘗試使用 generics。 (僅限 1.18+)
type SliceType interface {
~string | ~int | ~float64 // add more *comparable* types as needed
}
func removeDuplicates[T SliceType](s []T) []T {
if len(s) < 1 {
return s
}
// sort
sort.SliceStable(s, func(i, j int) bool {
return s[i] < s[j]
})
prev := 1
for curr := 1; curr < len(s); curr++ {
if s[curr-1] != s[curr] {
s[prev] = s[curr]
prev++
}
}
return s[:prev]
}
Go 游樂場鏈接與測試: https://go.dev/play/p/bw1PP1osJJQ
簡單易懂。
func RemoveDuplicate(array []string) []string {
m := make(map[string]string)
for _, x := range array {
m[x] = x
}
var ClearedArr []string
for x, _ := range m {
ClearedArr = append(ClearedArr, x)
}
return ClearedArr
}
減少 memory 的使用:
package main
import (
"fmt"
"reflect"
)
type void struct{}
func main() {
digits := [6]string{"one", "two", "three", "four", "five", "five"}
set := make(map[string]void)
for _, element := range digits {
set[element] = void{}
}
fmt.Println(reflect.ValueOf(set).MapKeys())
}
ps游樂場
如果您不想浪費 memory 分配另一個數組來復制值,您可以將值刪除,如下所示:
package main
import "fmt"
var studentsCities = []string{"Mumbai", "Delhi", "Ahmedabad", "Mumbai", "Bangalore", "Delhi", "Kolkata", "Pune"}
func contains(s []string, e string) bool {
for _, a := range s {
if a == e {
return true
}
}
return false
}
func main() {
fmt.Printf("Cities before remove: %+v\n", studentsCities)
for i := 0; i < len(studentsCities); i++ {
if contains(studentsCities[i+1:], studentsCities[i]) {
studentsCities = remove(studentsCities, i)
i--
}
}
fmt.Printf("Cities after remove: %+v\n", studentsCities)
}
func remove(slice []string, s int) []string {
return append(slice[:s], slice[s+1:]...)
}
結果:
Cities before remove: [Mumbai Delhi Ahmedabad Mumbai Bangalore Delhi Kolkata Pune]
Cities after remove: [Ahmedabad Mumbai Bangalore Delhi Kolkata Pune]
func UniqueNonEmptyElementsOf(s []string) []string {
unique := make(map[string]bool, len(s))
var us []string
for _, elem := range s {
if len(elem) != 0 {
if !unique[elem] {
us = append(us, elem)
unique[elem] = true
}
}
}
return us
}
將復制的接頭發送到上述 function,這將返回具有唯一元素的接頭。
func main() {
studentsCities := []string{"Mumbai", "Delhi", "Ahmedabad", "Mumbai", "Bangalore", "Delhi", "Kolkata", "Pune"}
uniqueStudentsCities := UniqueNonEmptyElementsOf(studentsCities)
fmt.Println(uniqueStudentsCities)
}
也可以使用類似集合的 map 來完成:
ddpStrings := []string{}
m := map[string]struct{}{}
for _, s := range strings {
if _, ok := m[scopeStr]; ok {
continue
}
ddpStrings = append(ddpStrings, s)
m[s] = struct{}{}
}
這是一個基於無映射索引的切片的重復“去除器”/修剪器。 它使用排序方法。
n
值始終比非重復元素的總數低 1,這是因為此方法將當前(連續/單個)元素與下一個(連續/單個)元素進行比較,並且在最后一個元素之后沒有匹配項,因此您必須填充它包括最后一個。
請注意,此代碼段不會將重復元素清空為 nil 值。 但是,由於n+1
integer 從重復項的索引開始,您可以從所述 integer 循環,並且將元素的 rest 歸零。
sort.Strings(strs)
for n, i := 0, 0; ; {
if strs[n] != strs[i] {
if i-n > 1 {
strs[n+1] = strs[i]
}
n++
}
i++
if i == len(strs) {
if n != i {
strs = strs[:n+1]
}
break
}
}
fmt.Println(strs)
基於Riyaz 的解決方案,您可以使用 generics 自 Go 1.18
func removeDuplicate[T string | int](tSlice []T) []T {
allKeys := make(map[T]bool)
list := []T{}
for _, item := range tSlice {
if _, value := allKeys[item]; !value {
allKeys[item] = true
list = append(list, item)
}
}
return list
}
Generics 最大限度地減少了代碼重復。
Go 游樂場鏈接: https://go.dev/play/p/Y3fEtHJpP7Q
到目前為止,@snassr 給出了最佳答案,因為它是 memory(無額外內存)和運行時(nlogn)方面最優化的方式。 但我想在這里強調的一件事是,如果我們想刪除數組的任何索引/元素,我們應該從頭到尾循環,因為它降低了復雜性。 如果我們從頭到尾循環,那么如果我們刪除nth
索引,那么我們將意外錯過第 n 個元素(在刪除第 n 個元素之前是第n+1th
個),因為在下一次迭代中我們將獲得第n+1th
元素。
func Dedup(strs []string) {
sort.Strings(strs)
for i := len(strs) - 1; i > 0; i-- {
if strs[i] == strs[i-1] {
strs = append(strs[:i], strs[i+1:]...)
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.