Go中的惯用拼接方式

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

Idiomatic Splice in Go

问题

我检查了一个现有的答案,但它与我的情况不相似。

我需要根据Compare函数,在运行时从索引中取出一个元素,并跳出for循环。

问题:
如果要取出的元素位于0索引处,index-1将引发切片越界错误,如果index+1大于len(elements)也会出现类似的问题。

问题:如何以最简洁的方式实现上述目标?

  1. for index, element := range elements {
  2. if element.Compare() == true {
  3. elements = append(elements[:index-1], elements[index+1:]...)
  4. break
  5. }
  6. }

尝试

  1. for index, element := range elements {
  2. if element.Compare() == true {
  3. if len(elements) > 1 {
  4. elements = append(elements[:index-1], elements[index+1:]...)
  5. } else if len(elements) == 1 {
  6. delete(elements, 0)
  7. }
  8. break
  9. }
  10. }

尝试2 Playground 有什么改进/建议吗?

思路是从开头复制剩余的元素到索引位置,然后复制后面的任何元素。

  1. var elements = []string {"a", "b", "c", "d"}
  2. fmt.Println(elements)
  3. for index, element := range elements {
  4. if element == "c" {
  5. var temp = elements[:index]
  6. for i := index + 1; i<len(elements); i++ {
  7. temp = append(temp, elements[i])
  8. }
  9. elements = temp
  10. break
  11. }
  12. }
  13. fmt.Println(elements)
英文:

I checked an existing answer but it's not similar to my case.

I need to pluck an element at the index and break out of the for loop at runtime based on Compare function.

Issues:
If element to pluck is found at 0 index, index-1 will throw slice bounds of range error and similarly if index+1 is greater than len(elements).

Question: What's the best concise way to achieve the above?

  1. for index, element := range elements {
  2. if element.Compare() == true {
  3. elements = append(elements[:index-1], elements[index+1:]...)
  4. break
  5. }
  6. }

Attempt

  1. for index, element := range elements {
  2. if element.Compare() == true {
  3. if len(elements) &gt; 1 {
  4. elements = append(elements[:index-1], elements[index+1:]...)
  5. } else if len(elements) == 1 {
  6. delete(elements, 0)
  7. }
  8. break
  9. }
  10. }

Attempt 2 Playground any improvements/suggestions?

The idea is to copy the remaining elements from beginning to index and then any elements after.

  1. var elements = []string {&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;d&quot;}
  2. fmt.Println(elements)
  3. for index, element := range elements {
  4. if element == &quot;c&quot; {
  5. var temp = elements[:index]
  6. for i := index + 1; i&lt;len(elements); i++ {
  7. temp = append(temp, elements[i])
  8. }
  9. elements = temp
  10. break
  11. }
  12. }
  13. fmt.Println(elements)

答案1

得分: 5

slice表达式中,高索引是不包含的。

这意味着你的示例是有缺陷的,也就是说不需要特殊处理。

正确的切片表达式是:

  1. elements = append(elements[:index], elements[index+1:]...)

如果index是第一个元素(0),那么elements[:0]将是一个空切片。

如果index是最后一个元素(len-1),那么elements[index+1:]也将是一个空切片,因为index+1将等于切片的长度。所以解决方案很简单:

  1. for index, element := range elements {
  2. if element.Compare() {
  3. elements = append(elements[:index], elements[index+1:]...)
  4. break
  5. }
  6. }

为了在Go Playground上演示,让我们用一个简单的索引检查替换Compare()方法:

  1. for _, idxToRemove := range []int{0, 2, 4} {
  2. s := []int{0, 1, 2, 3, 4}
  3. for i := range s {
  4. if i == idxToRemove {
  5. s = append(s[:i], s[i+1:]...)
  6. break
  7. }
  8. }
  9. fmt.Println(idxToRemove, ":", s)
  10. }

输出结果(在Go Playground上尝试):

  1. 0 : [1 2 3 4]
  2. 2 : [0 1 3 4]
  3. 4 : [0 1 2 3]
英文:

The high index in a slice expression is exclusive.

This means your example is flawed, and also that no special treatment is required.

The correct slicing expression is:

  1. elements = append(elements[:index], elements[index+1:]...)

If index is the first element (0), then elements[:0] will be an empty slice.

If index is the last element (len-1), then elements[index+1:] will also be an empty slice, as index+1 will be equal to the lenght of the slice. So the solution is simply:

  1. for index, element := range elements {
  2. if element.Compare() {
  3. elements = append(elements[:index], elements[index+1:]...)
  4. break
  5. }
  6. }

To demonstrate it on the Go Playground, let's substitute the Compare() method with a simple index check:

  1. for _, idxToRemove := range []int{0, 2, 4} {
  2. s := []int{0, 1, 2, 3, 4}
  3. for i := range s {
  4. if i == idxToRemove {
  5. s = append(s[:i], s[i+1:]...)
  6. break
  7. }
  8. }
  9. fmt.Println(idxToRemove, &quot;:&quot;, s)
  10. }

Output (try it on the Go Playground):

  1. 0 : [1 2 3 4]
  2. 2 : [0 1 3 4]
  3. 4 : [0 1 2 3]

答案2

得分: 0

如果切片s已排序且len(s)较大,则可以使用二分查找来查找x。例如,

  1. package main
  2. import (
  3. "fmt"
  4. "sort"
  5. )
  6. func pluck(s []string, x string) []string {
  7. i := sort.SearchStrings(s, x)
  8. if i >= 0 && i < len(s) && s[i] == x {
  9. s = append(s[:i], s[i+1:]...)
  10. }
  11. return s
  12. }
  13. func main() {
  14. s := []string{"a", "b", "c", "d"}
  15. fmt.Println(s)
  16. s = pluck(s, "b")
  17. fmt.Println(s)
  18. }

输出:

  1. [a b c d]
  2. [a c d]

如果切片s的顺序不需要保留,则可以交换元素。例如,

  1. package main
  2. import "fmt"
  3. func pluck(s []string, x string) []string {
  4. for i, v := range s {
  5. if v == x {
  6. s[i] = s[len(s)-1]
  7. s = s[:len(s)-1]
  8. break
  9. }
  10. }
  11. return s
  12. }
  13. func main() {
  14. s := []string{"a", "b", "c", "d"}
  15. fmt.Println(s)
  16. s = pluck(s, "b")
  17. fmt.Println(s)
  18. }

输出:

  1. [a b c d]
  2. [a d c]

否则,可以使用切片s的切片操作。例如,

  1. package main
  2. import "fmt"
  3. func pluck(s []string, x string) []string {
  4. for i, v := range s {
  5. if v == x {
  6. s = append(s[:i], s[i+1:]...)
  7. break
  8. }
  9. }
  10. return s
  11. }
  12. func main() {
  13. s := []string{"a", "b", "c", "d"}
  14. fmt.Println(s)
  15. s = pluck(s, "b")
  16. fmt.Println(s)
  17. }

输出:

  1. [a b c d]
  2. [a c d]
英文:

If the slice s is sorted and len(s) is large, find x using a binary search. For example,

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;sort&quot;
  5. )
  6. func pluck(s []string, x string) []string {
  7. i := sort.SearchStrings(s, x)
  8. if i &gt;= 0 &amp;&amp; i &lt; len(s) &amp;&amp; s[i] == x {
  9. s = append(s[:i], s[i+1:]...)
  10. }
  11. return s
  12. }
  13. func main() {
  14. s := []string{&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;d&quot;}
  15. fmt.Println(s)
  16. s = pluck(s, &quot;b&quot;)
  17. fmt.Println(s)
  18. }

Output:

  1. [a b c d]
  2. [a c d]

If the order of slice s does not need to be preserved, switch elements. For example,

  1. package main
  2. import &quot;fmt&quot;
  3. func pluck(s []string, x string) []string {
  4. for i, v := range s {
  5. if v == x {
  6. s[i] = s[len(s)-1]
  7. s = s[:len(s)-1]
  8. break
  9. }
  10. }
  11. return s
  12. }
  13. func main() {
  14. s := []string{&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;d&quot;}
  15. fmt.Println(s)
  16. s = pluck(s, &quot;b&quot;)
  17. fmt.Println(s)
  18. }

Output:

  1. [a b c d]
  2. [a d c]

Otherwise, splice slice s elements. For example,

  1. package main
  2. import &quot;fmt&quot;
  3. func pluck(s []string, x string) []string {
  4. for i, v := range s {
  5. if v == x {
  6. s = append(s[:i], s[i+1:]...)
  7. break
  8. }
  9. }
  10. return s
  11. }
  12. func main() {
  13. s := []string{&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;d&quot;}
  14. fmt.Println(s)
  15. s = pluck(s, &quot;b&quot;)
  16. fmt.Println(s)
  17. }

Output:

  1. [a b c d]
  2. [a c d]

答案3

得分: 0

我不确定这是否符合习惯用法,但这段代码运行得很好:

  1. package main
  2. import "fmt"
  3. func splice(start, count int, items []string) (ret []string) {
  4. ret = make([]string, len(items)-count)
  5. copy(ret, items[:start])
  6. copy(ret[start:], items[start+count:])
  7. return
  8. }
  9. func main() {
  10. s := []string{"a", "b", "c", "d"}
  11. fmt.Println(s)
  12. s = splice(1, 2, s)
  13. fmt.Println(s)
  14. }

Go Playground: https://play.golang.org/p/UNtdtw77sEQ

英文:

I'm not sure if this is idiomatic, but this works quite well:

  1. package main
  2. import &quot;fmt&quot;
  3. func splice(start, count int, items []string) (ret []string) {
  4. ret = make([]string, len(items)-count)
  5. copy(ret, items[:start])
  6. copy(ret[start:], items[start+count:])
  7. return
  8. }
  9. func main() {
  10. s := []string{&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;d&quot;}
  11. fmt.Println(s)
  12. s = splice(1, 2, s)
  13. fmt.Println(s)
  14. }

Go Playground: https://play.golang.org/p/UNtdtw77sEQ

huangapple
  • 本文由 发表于 2017年3月13日 04:09:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/42752500.html
匿名

发表评论

匿名网友

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

确定