Go中的惯用拼接方式

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

Idiomatic Splice in Go

问题

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

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

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

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

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

尝试

for index, element := range elements {
    if element.Compare() == true {
        if len(elements) > 1 {
            elements = append(elements[:index-1], elements[index+1:]...)
        } else if len(elements) == 1 {
            delete(elements, 0)
        }
        break
    }
}

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

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

var elements = []string {"a", "b", "c", "d"}
fmt.Println(elements)
for index, element := range elements {
    if element == "c" {
        var temp = elements[:index]
        for i := index + 1; i<len(elements); i++ {
            temp = append(temp, elements[i])
        }
        elements = temp
        break
    }
}
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?

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

Attempt

for index, element := range elements {
	if element.Compare() == true {
		if len(elements) &gt; 1 {
			elements = append(elements[:index-1], elements[index+1:]...)
		} else if len(elements) == 1 {
			delete(elements, 0)
		}
		break
	}
}

Attempt 2 Playground any improvements/suggestions?

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

var elements = []string {&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;d&quot;}
fmt.Println(elements)
for index, element := range elements {
	if element == &quot;c&quot; {
		var temp = elements[:index]
		for i := index + 1; i&lt;len(elements); i++ {
			temp = append(temp, elements[i])
		}
		elements = temp
		break
	}
}
fmt.Println(elements)

答案1

得分: 5

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

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

正确的切片表达式是:

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

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

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

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

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

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

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

0 : [1 2 3 4]
2 : [0 1 3 4]
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:

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:

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

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

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

Output (try it on the Go Playground):

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

答案2

得分: 0

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

package main

import (
	"fmt"
	"sort"
)

func pluck(s []string, x string) []string {
	i := sort.SearchStrings(s, x)
	if i >= 0 && i < len(s) && s[i] == x {
		s = append(s[:i], s[i+1:]...)
	}
	return s
}

func main() {
	s := []string{"a", "b", "c", "d"}
	fmt.Println(s)
	s = pluck(s, "b")
	fmt.Println(s)
}

输出:

[a b c d]
[a c d]

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

package main

import "fmt"

func pluck(s []string, x string) []string {
	for i, v := range s {
		if v == x {
			s[i] = s[len(s)-1]
			s = s[:len(s)-1]
			break
		}
	}
	return s
}

func main() {
	s := []string{"a", "b", "c", "d"}
	fmt.Println(s)
	s = pluck(s, "b")
	fmt.Println(s)
}

输出:

[a b c d]
[a d c]

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

package main

import "fmt"

func pluck(s []string, x string) []string {
	for i, v := range s {
		if v == x {
			s = append(s[:i], s[i+1:]...)
			break
		}
	}
	return s
}

func main() {
	s := []string{"a", "b", "c", "d"}
	fmt.Println(s)
	s = pluck(s, "b")
	fmt.Println(s)
}

输出:

[a b c d]
[a c d]
英文:

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

package main

import (
	&quot;fmt&quot;
	&quot;sort&quot;
)

func pluck(s []string, x string) []string {
	i := sort.SearchStrings(s, x)
	if i &gt;= 0 &amp;&amp; i &lt; len(s) &amp;&amp; s[i] == x {
		s = append(s[:i], s[i+1:]...)
	}
	return s
}

func main() {
	s := []string{&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;d&quot;}
	fmt.Println(s)
	s = pluck(s, &quot;b&quot;)
	fmt.Println(s)
}

Output:

[a b c d]
[a c d]

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

package main

import &quot;fmt&quot;

func pluck(s []string, x string) []string {
	for i, v := range s {
		if v == x {
			s[i] = s[len(s)-1]
			s = s[:len(s)-1]
			break
		}
	}
	return s
}

func main() {
	s := []string{&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;d&quot;}
	fmt.Println(s)
	s = pluck(s, &quot;b&quot;)
	fmt.Println(s)
}

Output:

[a b c d]
[a d c]

Otherwise, splice slice s elements. For example,

package main

import &quot;fmt&quot;

func pluck(s []string, x string) []string {
	for i, v := range s {
		if v == x {
			s = append(s[:i], s[i+1:]...)
			break
		}
	}
	return s
}

func main() {
	s := []string{&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;d&quot;}
	fmt.Println(s)
	s = pluck(s, &quot;b&quot;)
	fmt.Println(s)
}

Output:

[a b c d]
[a c d]

答案3

得分: 0

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

package main

import "fmt"

func splice(start, count int, items []string) (ret []string) {
	ret = make([]string, len(items)-count)
	copy(ret, items[:start])
	copy(ret[start:], items[start+count:])
    return
}

func main() {
    s := []string{"a", "b", "c", "d"}
    fmt.Println(s)
    s = splice(1, 2, s)
    fmt.Println(s)
}

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

英文:

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

package main

import &quot;fmt&quot;

func splice(start, count int, items []string) (ret []string) {
	ret = make([]string, len(items)-count)
	copy(ret, items[:start])
	copy(ret[start:], items[start+count:])
    return
}

func main() {
    s := []string{&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;d&quot;}
    fmt.Println(s)
    s = splice(1, 2, s)
    fmt.Println(s)
}

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:

确定