2

読書リストに記事の一部があります。各 Article には、記事の元となったフィードの URL を持つ "FeedURL" 属性があります。フィードの購読を解除するときに、そのフィードの URL を含むすべての記事を削除できるようにしたいと考えています。

type Article struct {
    FeedURL string
    URL     string // should be unique
    // ... more data
}

func unsubscribe(articleList []Article, url string) []Article {
   // how do I remove every Article from articleList that contains url?
}

func main() {
    myArticleList := []Article{
        Article{"http://blog.golang.org/feed.atom", "http://blog.golang.org/race-detector"},
        Article{"http://planet.python.org/rss20.xml", "http://archlinux.me/dusty/2013/06/29/creating-an-application-in-kivy-part-3/"},
        Article{"http://planet.python.org/rss20.xml", "http://feedproxy.google.com/~r/cubicweborg/~3/BncbP-ap0n0/2957378"},
        // ... much more examples
    }

    myArticleList = unsubscribe(myArticleList, "http://planet.python.org/rss20.xml")

    fmt.Printf("%+v", myArticleList)
}

この問題を解決する効率的な方法は何ですか?

最初、購読解除のコードは次のようになりました。

func unsubscribe(articleList []Article, url string) []Article {
    for _, article := range articleList {
        if article.FeedURL == url {
            articleList = append(articleList[:i], articleList[i+1:]...)
        }
    }
    return articleList
}

しかし、これによりスライスが変更され、for ループが予測不能になることに気付きました。

これを達成するための効率的できれいな方法は何ですか?

4

2 に答える 2

5

効率的にするには:

  • アーティクルへのポインタのスライスを使用すると、ポインタを構造値ではなく構造に移動します。
  • リスト内の記事の順序が重要でない場合は、順不同アルゴリズムを使用します。ポインターの動きを減らします。それ以外の場合は、順序付きアルゴリズムを使用します。いずれにせよ、ポインタの移動は最小限に抑えてください。
  • リストの最後にダングリング ポインターを残さないでください。ガベージ コレクターは、それらがまだ使用されていると見なします。スライスの長さではなく、スライスの容量を調べます。
  • メモリ割り当てを最小限に抑えます。

例えば、

package main

import "fmt"

type Article struct {
    FeedURL string
    URL     string // should be unique
    // ... more data
}

// Remove every Article from an articleList that contains url without preserving order.
func unsubscribeUnordered(a []*Article, url string) []*Article {
    for i := 0; i < len(a); i++ {
        if a[i].FeedURL == url {
            a[len(a)-1], a[i], a = nil, a[len(a)-1], a[:len(a)-1]
            i--
        }
    }
    return a
}

// Remove every Article from an articleList that contains url while preserving order.
func unsubscribeOrdered(a []*Article, url string) []*Article {
    j := 0
    for i := 0; i < len(a); i++ {
        if a[i].FeedURL == url {
            continue
        }
        if i != j {
            a[j] = a[i]
        }
        j++
    }
    for k := j; k < len(a); k++ {
        a[k] = nil
    }
    return a[:j]
}

func NewArticleList() []*Article {
    return []*Article{
        &Article{"http://blog.golang.org/feed.atom", "http://blog.golang.org/race-detector"},
        &Article{"http://planet.python.org/rss20.xml", "http://archlinux.me/dusty/2013/06/29/creating-an-application-in-kivy-part-3/"},
        &Article{"http://planet.python.org/rss20.xml", "http://feedproxy.google.com/~r/cubicweborg/~3/BncbP-ap0n0/2957378"},
        // ... much more examples
    }
}

func PrintArticleList(a []*Article) {
    fmt.Print("[")
    for _, e := range a {
        fmt.Printf("%+v", *e)
    }
    fmt.Println("]")
}

func main() {
    PrintArticleList(NewArticleList())
    ao := unsubscribeOrdered(NewArticleList(), "http://planet.python.org/rss20.xml")
    PrintArticleList(ao)
    auo := unsubscribeUnordered(NewArticleList(), "http://planet.python.org/rss20.xml")
    PrintArticleList(auo)
}

出力:

[{FeedURL:http://blog.golang.org/feed.atom URL:http://blog.golang.org/race-detector}{FeedURL:http://planet.python.org/rss20.xml URL:http://archlinux.me/dusty/2013/06/29/creating-an-application-in-kivy-part-3/}{FeedURL:http://planet.python.org/rss20.xml URL:http://feedproxy.google.com/~r/cubicweborg/~3/BncbP-ap0n0/2957378}]

[{FeedURL:http://blog.golang.org/feed.atom URL:http://blog.golang.org/race-detector}]
[{FeedURL:http://blog.golang.org/feed.atom URL:http://blog.golang.org/race-detector}]
于 2013-06-30T01:18:46.203 に答える
0

PeterSO の答えは、効率的に仕事を終わらせることです。

しかし、私はこのような単純なもので行くかもしれません

func unsubscribe(articleList []Article, url string) (filtered []Article) {
    filtered = articleList[:0] // optional.  reuses already-allocated memory.
    for _, article := range articleList {
        if article.FeedURL != url {
            filtered = append(filtered, article)
        }
    }
    return
}

読んで理解するのに約2秒しかかかりません。

このアイデアは、記事へのポインタでもうまく機能し、PeterSO が言ったように、Article 構造体が大きい場合、それは良いことかもしれません。

于 2013-06-30T21:07:32.713 に答える