7

次のコードがあります。

IEnumerable<KeyValuePair<T, double>> items =
    sequence.Select(item => new KeyValuePair<T, double>(item, weight(item)));
if (items.Any(pair => pair.Value<0))
    throw new ArgumentException("Item weights cannot be less than zero.");

double sum = items.Sum(pair => pair.Value);
foreach (KeyValuePair<T, double> pair in items) {...}

はどこweightですかFunc<T, double>

weight問題は、実行される回数をできるだけ少なくしたいということです。これは、アイテムごとに最大 1 回実行する必要があることを意味します。これを配列に保存することでこれを達成できました。ただし、重みが負の値を返す場合は、実行を続行したくありません。

LINQ フレームワーク内でこれを簡単に達成する方法はありますか?

4

6 に答える 6

15

確かに、それは完全に実行可能です:

public static Func<A, double> ThrowIfNegative<A, double>(this Func<A, double> f)
{
    return a=>
    { 
      double r = f(a);  
      // if r is NaN then this will throw.
      if ( !(r >= 0.0) )
        throw new Exception(); 
      return r;
    };
}

public static Func<A, R> Memoize<A, R>(this Func<A, R> f)
{
    var d = new Dictionary<A, R>();
    return a=>
    {
        R r;
        if (!d.TryGetValue(a, out r))
        {
          r = f(a);
          d.Add(a, r);
        }
        return r;
    };
}

そしていま...

Func<T, double> weight = whatever;
weight = weight.ThrowIfNegative().Memoize();

これで完了です。

于 2012-04-20T23:05:28.653 に答える
2

1 つの方法は、次のようにして、例外をweight関数に移動するか、少なくとも移動をシミュレートすることです。

Func<T, double> weightWithCheck = i =>
    {
        double result = weight(i);
        if (result < 0)
        {
            throw new ArgumentException("Item weights cannot be less than zero.");
        }
        return result;
    };

IEnumerable<KeyValuePair<T, double>> items =
    sequence.Select(item => new KeyValuePair<T, double>(item, weightWithCheck(item)));

double sum = items.Sum(pair => pair.Value);

この時点で、例外がある場合は、それを取得する必要があります。ただし、例外を確実に取得する前に列挙するitems必要がありますが、例外を取得すると、再度呼び出すことはありませんweight

于 2012-04-20T23:06:27.767 に答える
0

どちらの答えも適切です (例外をスローする場所と関数のメモ化)。

しかし、実際の問題は、LINQ 式を強制的に評価してリスト (または類似のもの) として保存しない限り、使用するたびに LINQ 式が評価されることです。これを変更するだけです:

sequence.Select(item => new KeyValuePair<T, double>(item, weight(item)));

これに:

sequence.Select(item => new KeyValuePair<T, double>(item, weight(item))).ToList();

于 2012-04-20T23:07:52.207 に答える
0

いいえ、これを行うための LINQ フレームワークにはまだ何もありませんが独自のメソッドを作成して linq クエリから呼び出すことができます (すでに多くの人が示しているように)。

個人的にはToList、最初のクエリを使用するか、Eric の提案を使用します。

于 2012-04-20T23:20:12.733 に答える
0

おそらく foreach ループでそれを行うことができます。1 つのステートメントでそれを行う方法を次に示します。

IEnumerable<KeyValuePair<T, double>> items = sequence
    .Select(item => new KeyValuePair<T, double>(item, weight(item)))
    .Select(kvp =>
    {
        if (kvp.Value < 0)
            throw new ArgumentException("Item weights cannot be less than zero.");
        else
            return kvp;
    }
    );
于 2012-04-20T23:13:24.840 に答える