14

Sum や Average などの Median メソッドを追加するために、C# で List オブジェクトをオーバーライドしたいと考えています。私はすでにこの機能を見つけました:

public static decimal GetMedian(int[] array)
{
    int[] tempArray = array;
    int count = tempArray.Length;

    Array.Sort(tempArray);

    decimal medianValue = 0;

    if (count % 2 == 0)
    {
        // count is even, need to get the middle two elements, add them together, then divide by 2
        int middleElement1 = tempArray[(count / 2) - 1];
        int middleElement2 = tempArray[(count / 2)];
        medianValue = (middleElement1 + middleElement2) / 2;
    }
    else
    {
        // count is odd, simply get the middle element.
        medianValue = tempArray[(count / 2)];
    }

    return medianValue;
}

その方法を教えていただけますか?

4

8 に答える 8

24

拡張メソッドを使用して、入力された配列/リストのコピーを作成します。

public static decimal GetMedian(this IEnumerable<int> source)
{
    // Create a copy of the input, and sort the copy
    int[] temp = source.ToArray();    
    Array.Sort(temp);

    int count = temp.Length;
    if (count == 0)
    {
        throw new InvalidOperationException("Empty collection");
    }
    else if (count % 2 == 0)
    {
        // count is even, average two middle elements
        int a = temp[count / 2 - 1];
        int b = temp[count / 2];
        return (a + b) / 2m;
    }
    else
    {
        // count is odd, return the middle element
        return temp[count / 2];
    }
}
于 2011-03-11T16:05:45.117 に答える
16

その機能を使用しないでください。それは深刻な欠陥です。これをチェックしてください:

int[] tempArray = array;     
Array.Sort(tempArray); 

配列はC# の参照型です。これは、コピーではなく、指定した配列をソートします。 配列の中央値を取得しても、その順序は変更されません。すでに別の順序でソートされている可能性があります。

Array.Copy最初に配列のコピーを作成し、次にコピーをソートするために使用します。

于 2011-03-11T15:59:08.383 に答える
6

私は間違いなくこれらのExtension Methodsを作成します:

public static class EnumerableExtensions
{
    public static decimal Median(this IEnumerable<int> list)
    {
        // Implementation goes here.
    }

    public static int Sum(this IEnumerable<int> list)
    {
        // While you could implement this, you could also use Enumerable.Sum()
    }
}

次に、これらのメソッドを次のように使用できます。

List<int> values = new List<int>{ 1, 2, 3, 4, 5 };
var median = values.Median();

アップデート

ああ...そして、Eric が言及しているように、Median の別の実装を見つける必要があります。あなたが提供したものは、元の配列をその場で変更するだけでなく、正しく読んでいれば、予想される小数ではなく整数も返します。

于 2011-03-11T15:53:43.247 に答える
0

Average と sum は、正しい変換関数をパラメーターMSDNとして提供する、任意の IEnumerable で使用可能な拡張メソッドです。

decimal Median<TSource>(this IEnumerable<TSource> collection, Func<TSource,decimal> transform)
{
   var array = collection.Select(x=>transform(x)).ToArray();
   [...]
   return median;
}

transform はコレクション項目を取り、それを小数に変換します (平均的で比較可能)

Median メソッドの実装の詳細についてはここでは触れませんが、それほど複雑ではありません。

編集:小数平均を出力するというさらなる要件を追加したのを見ました。

PS: 簡潔にするために、パラメーターのチェックは省略されています。

于 2011-03-11T16:05:25.507 に答える
0

サポートするコレクション型の拡張メソッドを作成できます。その後、あたかもそのクラスの一部であるかのように、それを呼び出すことができます。

MSDN - 拡張メソッドのドキュメントと例

于 2011-03-11T15:52:41.720 に答える
0

私はあなたの方法にいくつかの修正を加えます:

これを置き換えます:

     int[] tempArray = array; 

と:

     int[] tempArray = (int[])array.Clone();
于 2014-01-17T03:59:32.650 に答える
0

SQL サーバーに大きなテーブルがあり、.ToList() と .ToArray() がうまく機能しない独自のソリューションを作成しました (他の操作を行う前にデータベースからすべての行をプルします。単にレコードの長さが必要です。誰かが興味を持っている場合は、中央の1行または2行(奇数または偶数) 式を持つバージョンがあり、10進数の場合は代わりにTResultを返します

   public static decimal MedianBy<T, TResult>(this IQueryable<T> sequence, Expression<Func<T, TResult>> getValue)
{
    var count = sequence.Count();
    //Use Expression bodied fuction otherwise it won't be translated to SQL query
    var list = sequence.OrderByDescending(getValue).Select(getValue);
    var mid = count / 2;
    if (mid == 0)
    {
        throw new InvalidOperationException("Empty collection");
    }
    if (count % 2 == 0)
    {
        var elem1 = list.Skip(mid - 1).FirstOrDefault();
        var elem2 = list.Skip(mid).FirstOrDefault();

        return (Convert.ToDecimal(elem1) + Convert.ToDecimal(elem2)) / 2M;
        //TODO: search for a way to devide 2 for different types (int, double, decimal, float etc) till then convert to decimal to include all posibilites
    }
    else
    {
        return Convert.ToDecimal(list.Skip(mid).FirstOrDefault());
        //ElementAt Doesn't work with SQL
        //return list.ElementAt(mid);
    }
}
于 2016-07-26T04:12:52.983 に答える