3

誰かがこれを行うためのよりスマートな方法を持っていますか? これより簡単なはずですが、メンタルブロックがあります。基本的に、辞書からアイテムを削除し、辞書でもあるアイテムの値に再帰する必要があります。

private void RemoveNotPermittedItems(ActionDictionary menu)
{
    var keysToRemove = new List<string>();
    foreach (var item in menu)
    {
        if (!GetIsPermitted(item.Value.Call))
        {
            keysToRemove.Add(item.Key);
        }
        else if (item.Value is ActionDictionary)
        {
            RemoveNotPermittedItems((ActionDictionary)item.Value);
            if (((ActionDictionary)item.Value).Count == 0)
            {
                keysToRemove.Add(item.Key);
            }
        }
    }
    foreach (var key in (from item in menu where keysToRemove.Contains(item.Key) select item.Key).ToArray())
    {
        menu.Remove(key);
    }
}

アクション辞書は次のようになります。

public class ActionDictionary : Dictionary<string, IActionItem>, IActionItem
4

10 に答える 10

3

ディクショナリを逆に ('menu.Count - 1' から 0 まで) 反復する場合、キーを収集して再度反復する必要はありません。もちろん、順方向に反復すると、何かを削除し始めると、変異したコレクションの例外が発生します。

ActionDictionary が何であるかわからないため、正確なシナリオをテストできませんでしたが、Dictionary<string,object>.

    static int counter = 0;
    private static void RemoveNotPermittedItems(Dictionary<string, object> menu)
    {
        for (int c = menu.Count - 1; c >= 0; c--)
        {
            var key = menu.Keys.ElementAt(c);
            var value = menu[key];
            if (value is Dictionary<string, object>)
            {
                RemoveNotPermittedItems((Dictionary<string, object>)value);
                if (((Dictionary<string, object>)value).Count == 0)
                {
                    menu.Remove(key);
                }
            }
            else if (!GetIsPermitted(value))
            {
                menu.Remove(key);
            }
        }
    }

    // This just added to actually cause some elements to be removed...
    private static bool GetIsPermitted(object value)
    {
        if (counter++ % 2 == 0)
            return false;
        return true;
    }

「if」ステートメントも逆にしましたが、それは単に、アイテムの値に作用するメソッドを呼び出す前に型チェックを実行したいという仮定に過ぎませんでした。アクション辞書。

お役に立てれば。

于 2008-10-25T06:17:26.563 に答える
2

foreach と GetEnumerator が失敗する間、for ループが機能し、

var table = new Dictionary<string, int>() {{"first", 1}, {"second", 2}};
for (int i = 0; i < table.Keys.Count; i++)//string key in table.Keys)
{
    string key = table.Keys.ElementAt(i);
    if (key.StartsWith("f"))
    {
        table.Remove(key);
    }
}

しかし、ElementAt() は .NET 3.5 の機能です。

于 2008-10-25T04:44:43.693 に答える
2

まず、foreachループは必要以上に複雑です。ただ行う:

foreach (var key in keysToRemove)
{
    menu.Remove(key);
}

Dictionaryメソッドがないことに少し驚いていRemoveAllますが、そうは見えません...

于 2008-10-24T22:24:23.070 に答える
1

オプション1:辞書はまだコレクションです。menu.Valuesを繰り返し処理します。

menu.Valuesを反復処理し、反復処理しながらそれらを削除できます。値はソートされた順序で表示されません(これはあなたの場合は問題ないはずです)。foreachを使用するのではなく、forループを使用してインデックスを調整する必要がある場合があります。反復中にコレクションを変更すると、列挙子は例外をスローします。

(開発マシンMonを使用しているときに、コードを追加しようとします)

オプション2:カスタムイテレータを作成します。

WinformsのListBoxSelectedItemsから返される一部のコレクションには、実際にはコレクションが含まれていません。これらは、基になるコレクションのラッパーを提供します。WPFのCollectionViewSourceのようなものです。ReadOnlyCollectionも同様のことを行います。

ネストされた辞書を、単一のコレクションのように列挙できるものに「フラット化」できるクラスを作成します。コレクションからアイテムを削除するように見えるが、実際には現在のディクショナリから削除する削除関数を実装します。

于 2008-10-25T01:43:58.253 に答える
1

私はあなたがおそらくすでに良い解決策を見つけたことを知っていますが、あなたがあなたのメソッドシグネチャを変更することができれば「滑らかさ」の理由だけで(私はそれがあなたのシナリオでは適切でないかもしれないことを知っています):

private ActionDictionary RemoveNotPermittedItems(ActionDictionary menu)
{
 return new ActionDictionary(from item in menu where GetIsPermitted(item.Value.Call) select item)
.ToDictionary(d=>d.Key, d=>d.Value is ActionDictionary?RemoveNotPermittedItems(d.Value as ActionDictionary) : d.Value));
}

そして、新しい辞書を変更したり具体化したりすることなく、フィルタリングされたアイテムで辞書を使用できるいくつかの方法を見ることができます。

于 2012-05-16T16:53:58.533 に答える
1

おもう

public class ActionSet : HashSet<IActionItem>, IActionItem

bool Clean(ActionSet nodes)
    {
        if (nodes != null)
        {
            var removed = nodes.Where(n => this.IsNullOrNotPermitted(n) || !this.IsNotSetOrNotEmpty(n) || !this.Clean(n as ActionSet));

            removed.ToList().ForEach(n => nodes.Remove(n));

            return nodes.Any();
        }

        return true;
    }

    bool IsNullOrNotPermitted(IActionItem node)
    {
        return node == null || *YourTest*(node.Call);
    }

    bool IsNotSetOrNotEmpty(IActionItem node)
    {
        var hset = node as ActionSet;
        return hset == null || hset.Any();
    }

速く働かなければならない

于 2012-05-18T10:15:34.667 に答える
1

明日VSマシンに行くまでテストされていません:o

private void RemoveNotPermittedItems(ActionDictionary menu)
{
    foreach(var _checked in (from m in menu
                             select new
                             {
                                 gip = !GetIsPermitted(m.Value.Call),
                                 recur = m.Value is ActionDictionary,
                                 item = m
                             }).ToArray())
    {
        ActionDictionary tmp = _checked.item.Value as ActionDictionary;
        if (_checked.recur)
        {
            RemoveNotPermittedItems(tmp);
        }
        if (_checked.gip || (tmp != null && tmp.Count == 0) {
            menu.Remove(_checked.item.Key);
        }
    }
}
于 2012-05-18T03:06:06.170 に答える
1

私の意見ではKeyValuePair<...>、TKey と TValue の両方から派生する独自のジェネリック クラスを定義でき、派生クラスの新しいまたはメソッドでまたはをList<T>使用して、必要なアイテムを削除できます。RemoveAllRemoveRangeList<T>RemoveRange()RemoveAll()

于 2012-05-12T17:45:36.180 に答える
1

の型をkeysToRemoveto に変更するHashSet<string>と、O(1)Containsメソッドが得られます。これList<string>は O(n) であり、ご想像のとおり低速です。

于 2012-05-17T17:22:37.557 に答える
1

それほど複雑ではありませんが、いくつかの慣用的な変更により、少し短くなり、見やすくなっています。

    private static void RemoveNotPermittedItems(IDictionary<string, IActionItem> menu)
    {
        var keysToRemove = new List<string>();

        foreach (var item in menu)
        {
            if (GetIsPermitted(item.Value.Call))
            {
                var value = item.Value as ActionDictionary;

                if (value != null)
                {
                    RemoveNotPermittedItems(value);
                    if (!value.Any())
                    {
                        keysToRemove.Add(item.Key);
                    }
                }
            }
            else
            {
                keysToRemove.Add(item.Key);
            }
        }

        foreach (var key in keysToRemove)
        {
            menu.Remove(key);
        }
    }

    private static bool GetIsPermitted(object call)
    {
        return ...;
    }
于 2012-05-17T15:41:57.687 に答える