1

次の例があります。

public class Commands
{
    public int ID { get; set; }
    public List<string> Alias { get; set; }
}

public class UserAccess
{
    public int AccessID { get; set; }
    // other stuff not needed for the question
    public List<Commands> AllowedCommands { get; set; }
}

ここで、リストにエイリアスが見つからなかった場合にコマンド ID または NULL を返す方法を UserAccess に実装したいと考えました。以下の汚い例を参照してください HasCommand

public class UserAccess
{
    public ID { get; set; }
    // other stuff not needed for the question
    public List<Commands> AllowedCommands { get; set; }

    public Commands HasCommand(string cmd)
    {
        foreach (Commands item in this.AllowedCommands)
        {
            if (item.Alias.Find(x => string.Equals(x, cmd, StringComparison.OrdinalIgnoreCase)) != null)
                return item;
        }
        return null;
    }
}
  • 私の質問は、 HasCommand メソッドを実行または実装する最も効率的な方法は何ですか?

  • または、それを UserAccess に実装するより良い方法はありますか?

4

4 に答える 4

6

少し短縮できます

public Commands HasCommand(string cmd)
{
    return AllowedCommands.FirstOrDefault(c => c.Alias.Contains(cmd, StringComparer.OrdinalIgnoreCase));

}

しかし、それはほとんど同じことです。

于 2011-10-04T17:35:27.113 に答える
2
public Commands HasCommand(string cmd)
    {
        return this.AllowedCommands.FirstOrDefault(item => item.Alias.Find(x => string.Equals(x, cmd, StringComparison.OrdinalIgnoreCase)) != null);
    }

Where+FirstOrDefaultを使用する必要はありません。FirstOfDefaultは条件を持つことができます。

于 2011-10-04T17:55:18.260 に答える
0

また、さらに改善するための 3 つの提案:

(1) 可能であれば、List の代わりに IEnumerable を使用することをお勧めします。
(2) 「コマンド」を単に「コマンド」と呼びます。
(3) 次のようなクラスを介してすべてのコマンドを簡単に参照できるようにします。

public class Command {
    public Command(int id, IEnumerable<string> aliases) {
        Id = id;
        Aliases = alias;
    }

    public int Id { get; set; }         
    public IEnumerable<string> Aliases { get; set; }  
}

public class Commands {
    public static readonly Command CommandNameHere1(yourIdHere1, yourAliasesHere1);
    public static readonly Command CommandNameHere2(yourIdHere2, yourAliasesHere2);
    //etc.
}
于 2011-10-04T17:52:46.563 に答える
0

「効率的」とは、文字列のコレクションで文字列を検索するときはいつでも高速を意味し、そのコレクションに複数のエントリが含まれる可能性があると仮定すると、常にハッシュ検索を使用する必要があります。リストの単純なスキャンを実行すると、アイテムの数が増えるにつれて指数関数的な時間がかかりますが、カウントはハッシュ ルックアップにはほとんど影響しません。.NET では、これは伝統的に Dictionary クラスによって処理されてきました。このクラスは、キー (多くの場合、文字列) を使用してオブジェクトのコレクションにインデックスを付けるために一般的に使用されます。ただし、値を null にすることはできません。これにより、キーと値の両方に同じ文字列が渡されるようになりました。これはかなり見苦しいものでした。最後に、.NET 4 は HashSet を提供しました。これは、キーのみを持ち、値を持たない場合に使用する必要があります。

あなたの場合、大文字と小文字を区別しない比較が必要な(珍しいことではない)状況があります。これに対する一般的な解決策は、辞書 (または HashSet) に追加するときに文字列キーを小文字にすることです。大文字と小文字を区別しない比較は、大文字と小文字を区別するよりもはるかに遅いことをすべてのプログラマーが認識し、理解する必要があるため、特に Unicode では、CPU はデータのブロック比較だけを実行することはできません。 、ただし、文字の各ペアを特別にチェックする必要があります (テーブル ルックアップを使用しても、これは非常に遅くなります)。

エイリアス名を小文字にできる場合は、それらを List から HashSet に変更します。そうでない場合は、キーが小文字として追加され、値が (大文字と小文字が混在する) エイリアス文字列である Dictionary を使用します。Dictionary を使用すると仮定すると、コードは次のようになります。

public Commands HasCommand(string cmd)
{
    foreach (Commands item in AllowedCommands)
    {
        if (item.Alias.ContainsKey(cmd))
            return item;
    }
    return null;
}

最後に、パフォーマンスに関しても、LINQ を使用すると、ほとんどの場合、パフォーマンスが低下します。状況に応じて、少し遅くなったり、大幅に遅くなったりします。それはシンプルなもののための素敵でコンパクトなソースを作ります.もちろん)。

したがって、できるだけ少ないコード行が必要な場合は、ここに投稿された他の回答を使用してください。速度が必要な場合は、私のものを使用してください。

言うまでもありませんが、このようなコードの小さなチャンクのパフォーマンスが心配な場合は、それを for ループでラップし、実行に 5 ~ 10 秒かかるまで繰り返します。 1,000 回でも 1,000,000 回でも必要であり、System.Diagnostics.Stopwatch で時間を計測します。別のロジックを試して、テストを繰り返します。5 ~ 10 秒は、管理された環境や同じマシンで実行されている他のものによって引き起こされる変動をマスクするように設計された最小値です (テスト中に他のアプリを実行することも明らかに避ける必要があります)。もちろん、複雑なアプリケーションの全体的なパフォーマンス テストには、パフォーマンス アナライザー ツールをお勧めします。

于 2011-10-04T18:13:21.543 に答える