2

私はクラスを持っていobjます。これには3つのプロパティがあります:、、、すべてfirstValue0から255の範囲です。secondValuethirdValue

クラスのオブジェクトを含むリストobjあり、、、およびの値に従って、それらを32の異なる領域に分割する必要がfirstValueありsecondValueますthirdValue。私は次のようなネストされたif-elseステートメントを使用して成功しました:

if (obj.firstValue < 15 )
{
    if(obj.secondValue <200)
    {
        if(obj.thirdValue <125)
            maincolor[0]++;
        else
            maincolor[1]++;
    }
    else
    {
        if (obj.thirdValue < 125)
            maincolor[2]++;
        else
            maincolor[3]++;
    }
}
else if (obj.firstValue < 41)
{
    if (obj.secondValue < 200)
    {
        if (obj.thirdValue < 125)
            maincolor[4]++;
        else
            maincolor[5]++;
    }
    else
    {
        if (obj.thirdValue < 125)
            maincolor[6]++;
        else
            maincolor[7]++;
    }
}
else if (obj.firstValue < 90)
{
    if (obj.secondValue < 200)
    {
        if (obj.thirdValue < 125)
            maincolor[8]++;
        else
            maincolor[9]++;
    }
    else
    {
        if (obj.thirdValue < 125)
            maincolor[10]++;
        else
            maincolor[11]++;
    }
}
else if (obj.firstValue < 128)
{
    if (obj.secondValue < 200)
    {
        if (obj.thirdValue < 125)
            maincolor[12]++;
        else
            maincolor[13]++;
    }
    else
    {
        if (obj.thirdValue < 125)
            maincolor[14]++;
        else
            maincolor[15]++;
    }
}
else if (obj.firstValue < 166)
{
    if (obj.secondValue < 200)
    {
        if (obj.thirdValue < 125)
            maincolor[16]++;
        else
            maincolor[17]++;
    }
    else
    {
        if (obj.thirdValue < 125)
            maincolor[18]++;
        else
            maincolor[19]++;
    }
}
else if (obj.firstValue < 196)
{
    if (obj.secondValue < 200)
    {
        if (obj.thirdValue < 125)
            maincolor[20]++;
        else
            maincolor[21]++;
    }
    else
    {
        if (obj.thirdValue < 125)
            maincolor[22]++;
        else
            maincolor[23]++;
    }
}
else if (obj.firstValue < 205)
{
    if (obj.secondValue < 200)
    {
        if (obj.thirdValue < 125)
            maincolor[24]++;
        else
            maincolor[25]++;
    }
    else
    {
        if (obj.thirdValue < 125)
            maincolor[26]++;
        else
            maincolor[27]++;
    }
}
else
{
    if (obj.secondValue < 200)
    {
        if (obj.thirdValue < 125)
            maincolor[28]++;
        else
            maincolor[29]++;
    }
    else
    {
        if (obj.thirdValue < 125)
            maincolor[30]++;
        else
            maincolor[31]++;
    }
}

maincolor[i]リージョンの最大数を記録するために使用します。

上記の方法は機能しますが、読みやすく、パフォーマンスコストを削減する方法があるかどうかを知りたいですか?

4

7 に答える 7

2

テストされていませんが、ドリフトが発生します。

編集:早期の救済を可能にするためにアルゴリズムを逆にしました。

int[] firstCutoffs = new int[] { 15, 41, 90, 128, 166, 196, 205 };
int index;

for (int n = 0; obj.firstValue > firstCutoffs[n] && n < firstCutoffs.Length; n++)
    index += 4;

if (obj.secondValue >= 200 )
    index += 2;

if (obj.thirdValue >= 125 )
    index ++;

maincolor[index]++;
于 2012-09-06T08:05:19.687 に答える
1

ネストされたif条件が 3 つある場合、何か間違ったことをしていることはほぼ確実です。

C# はオブジェクト指向言語なので、オブジェクトを考えなければなりません。

例えば:

class ColorRange
{
    public Range RedRange { get; set; }
    public Range GreenRange { get; set; }
    public Range BlueRange { get; set; }
}

class Range
{
    public int Minimum { get; set; }
    public int Maximum { get; set; }

    public bool IsInRange(int value)
    {
        return value >= this.Minimum && value < this.Maximum;
    }
}

次に、GetColorRangeどこかにメソッドを作成します。

public ColorRange GetColorRange(int red, int green, int blue)
{
    foreach (var colorRange in this.Ranges)
    {
        if (colorRange.RedRange.IsInRange(red)
            && colorRange.GreenRange.IsInRange(green)
            && colorRange.BlueRange.IsInRange(blue))
        {
            return colorRange;
        }
    }

    return null;

    /*
        Or with Linq:
        return this.Ranges.FirstOrDefault(colorRange => 
            colorRange.RedRange.IsInRange(red)
            && colorRange.GreenRange.IsInRange(green)
            && colorRange.BlueRange.IsInRange(blue));
    */
}

使用法:

var colorRange = GetColorRange(20, 175, 200);

// increment the count of this color range in your array

もちろん、このコードを「そのまま」使用することは想定されていません。アルゴリズムを再設計する方法を示すだけです。

于 2012-09-06T08:11:22.883 に答える
0

私はこの質問が好きでした、私は少しのLinQでこれを試しました

    Dictionary<int,int> firstValue = new Dictionary<int,int>();
    firstValue.Add(15,0);
    firstValue.Add(41,4);
    firstValue.Add(90,8);
    firstValue.Add(128,12);
    firstValue.Add(166,16);
    firstValue.Add(196,20);
    firstValue.Add(205,24);
    firstValue.Add(256,28);

    int mainIndex = 0;
    KeyValuePair<int,int> firstIndex = firstValue.FirstOrDefault(x => obj.firstValue < x.Key);
    mainIndex = firstIndex.Value;
    mainIndex += (obj.secondValue < 200 ? 0 : 2);
    mainIndex += (obj.thirdValue < 125 ? 0 : 1);
    maincolor[mainIndex]++;  

まず、firstValueのすべてのテスト条件値を、メインカラーの適切なベースインデックスを使用してディクショナリに保存しました。次に、残りの値をインデックスに追加するための単純な数学演算です。利点は、Dictionaryaddメソッドで制限を明確に示すことです。

于 2012-09-06T08:18:58.133 に答える
0

コードを読みやすくするために、3 次元配列を使用してメインの色カテゴリを格納できます。

int[,,] mainColorCategories = new int [8,2,2];

(最初の値には 8 つのカテゴリがあり、2 番目と 3 番目の値には 2 つのカテゴリがあることに注意してください)

それに応じて、インデックスをメイン カラー配列に入力します。次に、コードを実装するには、この配列へのインデックスを決定する 3 つの関数を実装します。これらの関数は、コード スニペットで実行する "if-else-if" 評価を実行する必要があります。

int firstValueIndex = getFirstValueIndex(obj.firstValue);
int secondValueIndex = getSecondValueIndex(obj.secondValue);
int thirdValueIndex = getThirdValueIndex(obj.thirdValue);

次に、正しいメインカラー配列をインクリメントできます

int mainColorCat = mainColorCategories[firstValueIndex,secondValueIndex,thirdValueIndex];
maincolor[mainColorCat]++;
于 2012-09-06T08:07:11.730 に答える
0

私はあなたが答えを受け入れたので、あなたの検討のためにこれを鍋に投げ入れると思いました.

int index = 0;

if (obj.firstValue < 15)
    index = 0;
else if (obj.firstValue < 41)
    index = 4;
else if (obj.firstValue < 90)
    index = 8;
else if (obj.firstValue < 128)
    index = 12;
else if (obj.firstValue < 166)
    index = 16;
else if (obj.firstValue < 196)
    index = 20;
else if (obj.firstValue < 205)
    index = 24;
else
    index = 28;

if (obj.secondValue >= 200)
    index += 2;

if (obj.thirdValue >= 125)
    index++;

maincolor[index]++;

元の投稿されたコードに比べてはるかに見やすく、同じパフォーマンスを発揮します。


元のコードと私のコードと投稿された他の回答のパフォーマンスの違いを知りたいと思っていましたが、ループを使用するとパフォーマンスが低下することが明らかになりました。@GazTheDestroyer の回答に、これ以上速くなることはないとコメントしました (ループの巻き戻し > en.wikipedia.org/wiki/Loop_unwinding を参照)。

そこで、さまざまな回答を比較するための小さなプログラムを作成しましたが、一般的に、@mbm 回答などのループ タイプの回答ははるかに遅いことがわかりました。ここでの注意点は、反復するオブジェクトが多数ある場合にのみパフォーマンスの低下が顕著になることです。そのため、私のアプリでは 1000000 個のアイテム (1 番目、2 番目、3 番目のプロパティを持つオブジェクト) でテストしました。

1000000 アイテムの結果のアイデアを提供するためだけに:

  • 元のコードと上記のサンプル コードは、約 120 ミリ秒で実行されます
  • @mbm と @Steve の両方の回答 (ループを使用) は、それぞれ約 650 ミリ秒と 750 ミリ秒で実行されます。はるかに遅い!

プログラムのコードを github > https://github.com/mouters/SO12295374_SpeedTestにアップロードしたので、自由にダウンロードしてテストしてください。

于 2012-09-07T09:23:30.000 に答える
0

この回答は、ここでのほとんどの回答とほぼ同じです。ここで一致する値を見つけたら、ブレークの使用を強調したいだけです。

        int[] limitList = new int[] { 15, 41, 90, 128, 166, 196, 205 };
        int index = 0;
        foreach(int val in limitList)
        {
            if (obj.firstValue < val)
                break; //break on first encounter
            index += 4;
        }

        if (obj.secondValue >= 200)
            index+=2;

        if (obj.thirdValue >=125)
            index++;

        maincolor[index]++;
于 2012-09-06T08:27:53.970 に答える
-1

LINQを使用すると、ある程度の読みやすさを得ることができます。

// be allObjects an IEnumerable<obj>
maincolor[0] = allObjects.Count(o => o.firstValue < 15 && o.secondValue < 200 && o.thirdValue < 125);
于 2012-09-06T08:05:49.297 に答える