从切片中删除所有相同元素的出现。

huangapple go评论83阅读模式
英文:

Remove all occurrences of the same element from slice

问题

我有以下代码:

func TestRemoveElement(t *testing.T) {
    nums := []int{3, 2, 2, 3}
    result := removeElement(nums, 3)

    if result != 2 {
        t.Errorf("期望值为 2,但实际值为 %d。", result)
    }
}

func removeElement(nums []int, val int) int {

    for i := 0; i < len(nums); i++ {
        if nums[i] == val {
            nums = append(nums[:i], nums[i+1:]...)
            i-- // 删除元素后,需要将索引减1
        }
    }
    return len(nums)
}

if 语句中的语句是根据这个答案中最常用的一种在切片中替换元素的方式。但是由于 i+1,它无法删除最后一个元素。也就是说,如果在最后一个元素中找到匹配项,i+1 就会超出范围。有没有更好的方法来替换元素并考虑最后一个元素呢?

英文:

I have the following code:

func TestRemoveElement(t *testing.T) {
	nums := []int{3, 2, 2, 3}
	result := removeElement(nums, 3)

	if result != 2 {
		t.Errorf(&quot;Expected 2, but it was %d instead.&quot;, result)
	}
}

func removeElement(nums []int, val int) int {

	for i, v := range nums {
		if v == val {
			nums = append(nums[:i], nums[i+1:]...)
		}
	}
	return len(nums)
}

The statement inside the if statement is the most popular way of replacing an element in a slice per this answer. But this fails deleting the last element due to i+1. i.e if a match is found in the last element, i+1 is out of bounds. What better way to replace elements that considers last elements?

答案1

得分: 2

看起来你想要移除所有等于val的元素。一种方法是将不等于val的值复制到切片的开头:

func removeElement(nums []int, val int) []int {
    j := 0
    for _, v := range nums {
        if v != val {
            nums[j] = v
            j++
        }
    }
    return nums[:j]
}

返回新的切片而不是返回长度会更方便调用者使用。

如果你只想移除第一个等于val的元素,可以使用以下代码:

func removeElement(nums []int, val int) []int {
    for i, v := range nums {
        if v == val {
            return append(nums[:i], nums[i+1:]...)
        }
    }
    return nums
}
英文:

It looks like you are trying to remove all elements equal to val. One way to do this is to copy values not equal to val to the beginning of the slice:

func removeElement(nums []int, val int) []int {
	j := 0
	for _, v := range nums {
		if v != val {
			nums[j] = v
			j++
		}
	}
	return nums[:j]
}

Return the new slice instead of returning the length. It will be more convenient for the caller.

If you only want to remove the first element equal to val, then use this code:

func removeElement(nums []int, val int) []int {
	for i, v := range nums {
		if v == val {
			return append(nums[:i], nums[i+1:]...)
		}
	}
	return nums
}

答案2

得分: 1

添加索引检查可以解决你的问题。Copyappend具有更好的性能,但你原来的append版本仍然可以工作。如果你正在使用切片,这是一个很好的页面,可以放入你的Go工具库中。另外请注意,下面的函数不会更新你传入的切片,所以虽然它会打印出删除了多少个项目,但原始切片不会删除这些项目。

func removeElement(nums []int, val int) int {
    var i int
    for {
        if i == len(nums) {
            break
        }

        if nums[i] == val {
            nums = nums[:i+copy(nums[i:], nums[i+1:])]
            i = 0
        }
        i++
    }
    return len(nums)
}

修改后的removeElement函数还返回修改后的列表。

func removeElement(nums []int, val int) (numberOfItemsRemoved int, newArr []int) {
    var i int
    for {
        if i == len(nums) {
            break
        }

        if nums[i] == val {
            nums = nums[:i+copy(nums[i:], nums[i+1:])]
            i = 0
        }
        i++
    }
    return len(nums), nums
}

你也可以通过引用修改原始切片,这样就不需要返回它了。

func removeElement(nums *[]int, val int) int {
    var i int
    for {
        if i == len(*nums) {
            break
        }
        slice := (*nums)
        if slice[i] == val {
            slice = slice[:i+copy(slice[i:], slice[i+1:])]
            *nums = slice
            i = 0
        }
        i++
    }
    return len(*nums)
}

示例用法:https://goplay.space/#leulqgwsjc

英文:

Adding an index check solves your issue. Copy has better performance than append but your original append version will still work. https://gist.github.com/xogeny/b819af6a0cf8ba1caaef

If you are working with slices this is a good page to have in your Go arsenal https://github.com/golang/go/wiki/SliceTricks

Also note that the function below doesn't update the slice you passed in, so while it will print how many items where removed, the original slice will not have those items removed.

func removeElement(nums []int, val int) int {
	var i int
	for {
		if i == len(nums) {
			break
		}

		if nums[i] == val {
			nums = nums[:i+copy(nums[i:], nums[i+1:])]
			i = 0
		}
		i++
	}
	return len(nums)
}

Modified removeElements that also returns the modded list

func removeElement(nums []int, val int) (numberOfItemsRemoved int, newArr []int) {
	var i int
	for {
		if i == len(nums) {
			break
		}

		if nums[i] == val {
			nums = nums[:i+copy(nums[i:], nums[i+1:])]
			i = 0
		}
		i++
	}
	return len(nums), nums
}

https://goplay.space/#1yfhTkZC4o

You can also modify the original slice by reference so that it doesn't have to be returned

func removeElement(nums *[]int, val int) int {
	var i int
	for {
		if i == len(*nums) {
			break
		}
		slice := (*nums)
		if slice[i] == val {
			slice = slice[:i+copy(slice[i:], slice[i+1:])]
			*nums = slice
			i = 0
		}
		i++
	}
	return len(*nums)
}

Example usage https://goplay.space/#leulqgwsjc

huangapple
  • 本文由 发表于 2017年9月5日 07:11:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/46044981.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定