4

最近LINQを発見しましたが、使用するのは非常に興味深いと思います。現在、私は次の機能を持っていますが、それがより効率的であるかどうかはわかりませんが、結局のところ、同じ出力を生成します。

これについてのご意見をお聞かせください。

この関数は、非常に簡単な方法で句読点を削除するだけです。

private static byte[] FilterText(byte[] arr)
    {
        List<byte> filteredBytes = new List<byte>();
        int j = 0; //index for filteredArray

        for (int i = 0; i < arr.Length; i++)
        {
            if ((arr[i] >= 65 && arr[i] <= 90) || (arr[i] >= 97 && arr[i] <= 122) || arr[i] == 10 || arr[i] == 13 || arr[i] == 32)
            {
                filteredBytes.Insert(j, arr[i]) ;
                j++;
            }
        }

        //return the filtered content of the buffer
        return filteredBytes.ToArray();
    }

LINQの代替:

    private static byte [] FilterText2(byte[] arr)
    {
        var x = from a in arr
                where ((a >= 65 && a <= 90) || (a >= 97 && a <= 122) || a == 10 || a == 13 || a == 32)
                select a;

        return x.ToArray();
    }
4

6 に答える 6

14

LINQは通常、単純なループや手続き型コードよりもわずかに効率が低くなりますが、違いは通常小さく、簡潔で読みやすいため、通常、単純な射影とフィルタリングをLINQに変換する価値があります。

パフォーマンスが本当に重要な場合は、それを測定し、LINQコードのパフォーマンスが適切かどうかを自分で判断してください。

于 2012-05-17T18:08:04.213 に答える
4

ネジの性能、LINQはこのために素晴らしいです:

private static bool IsAccepted(byte b)
{
    return (65 <= b && b <= 90) || 
           (97 <= b && b <= 122) || 
           b == 10 || b == 13 || b == 32;
}

arr.Where(IsAccepted).ToArray(); // equivalent to FilterText(arr)

つまり、あなたはどのように書くのではなく、何を書くのか。また、それはあなたが提示した他の方法とほぼ同じくらい速い(遅い)です:内部的にリストを作成し、それを配列iircに変換するWhere(..)怠惰に評価されます。ToArray()

ちなみに、文字列はC#ではUnicodeであるため、これを使用して単純な文字列フォーマットを実行しないでください(これにははるかに優れた代替手段があります)。

于 2012-05-17T18:27:17.367 に答える
4

LinQは、物事をシンプルに保つのに最適です。パフォーマンスに関しては、リストや配列などに多くの変換を開始すると、実際に問題になる可能性があります。

MyObject.where(...).ToList().something().ToList().somethingelse.ToList();

これはキラーであることがよく知られています。できるだけ遅く最終リストに変換してみてください。

于 2012-05-17T18:14:38.230 に答える
2

ほとんどの場合、私は@MarkByersに同意します。Linqは、手続き型コードよりも少し効率が悪くなります。一般に、欠陥は式ツリーのコンパイルに起因する可能性があります。それにもかかわらず、読みやすさと時間の改善は、99%のケースでヒットする価値があります。パフォーマンスの問題が発生した場合は、ベンチマーク、変更、および再ベンチマークを行ってください。

そうは言っても、LINQはラムダと匿名デリゲートと非常に密接に関連しています。これらの機能は、同じものであるかのようによく話されます。これらの構成は手続き型コード よりも高速な場合があります。あなたの例はそのようなケースの1つである可能性があります。私はあなたのコードを次のように書き直します:

private static byte [] FilterText2(byte[] arr) {

   return arr.Where( a=> (a >= 65 && a <= 90)  || 
                         (a >= 97 && a <= 122) || 
                          a == 10 || a == 13   || a == 32
                  ).ToArray();
}

繰り返しになりますが、YMMVのように、特定のシナリオに対していくつかのベンチマークを実行します。大量のインクがこぼれましたが、どちらがより速く、どのシナリオで実行されましたか。そのインクの一部を次に示します。

于 2012-05-17T18:28:37.707 に答える
1

多くのLINQステートメントは簡単に並列化できます。AsParallel()クエリの先頭に 追加するだけです。AsOrdered()パフォーマンスを犠牲にして元の注文を保持したい場合は、追加することもできます。たとえば、次のLINQステートメント:

arr.Where(IsAccepted).ToArray();

次のように書くことができます:

arr.AsParallel().AsOrdered().Where(IsAccepted).ToArray();

そのオーバーヘッドがその利点を上回らないことを確認する必要があります:

var queryA = from num in numberList.AsParallel()
             select ExpensiveFunction(num); //good for PLINQ

var queryB = from num in numberList.AsParallel()
             where num % 2 > 0
             select num; //not as good for PLINQ
于 2012-05-20T20:27:40.967 に答える
1

すべての優れた命令型コードは、優れた宣言型コードよりも時間とスペースの効率が高くなります。これは、その宣言型コードを命令型コードに変換する必要があるためです(ただし、Prologマシンを所有している場合を除きます。 .Net :-))。

ただし、ループを使用するよりも簡単で読みやすい方法でLINQを使用して問題を解決できる場合は、それだけの価値があります。あなたがのようなものを見たとき

var actualPrices = allPrices
    .Where(price => price.ValidFrom <= today && price.ValidTo >= today)
    .Select(price => price.PriceInUSD)
    .ToList();

それは一目でそれが何をしているのかが明らかな「一行」です。新しいコレクションを宣言し、古いコレクションをループし、ifを記述し、新しいコレクションに何かを追加することはできません。したがって、ミリ秒ごとに節約したくない場合は、それがメリットになります(ASMが組み込まれたCではなく.Netを使用しているため、おそらく節約しません)。そして、LINQは高度に最適化されています-より多くのコードベースがあります-1つはコレクション用、1つはXML用、もう1つはSQL用です...したがって、一般的にそれほど遅くはありません。使用しない理由はありません。

一部のLINQ式は、Parallel LINQを使用して、ほぼ「無料」で簡単に並列化できます(=コードはもうありませんが、並列処理のオーバーヘッドはまだ残っているので、それを考慮してください)。

于 2013-06-03T11:09:02.530 に答える