2

我有一个类obj,它具有三个属性:firstValuesecondValuethirdValue,所有这些属性的范围都在 0 到 255 之间。

我有一个包含类对象的列表obj必须根据 和 的值将它们分成 32 个不同的区域。我已经成功地使用了这样的嵌套 if-else 语句:firstValuesecondValuethirdValue

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条件时,你几乎可以肯定你做错了什么。

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

为了使代码更具可读性,您可以使用 3 维数组来存储主要颜色类别。

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

(注意,第一个值有 8 个类别,第二个和第三个有 2 个)

将索引相应地填充到主颜色数组中。然后要实现您的代码,您将实现三个函数来确定该数组的索引。这些函数需要执行您在代码片段中执行的“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

我喜欢这个问题,我用一点 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 的所有测试条件值存储在具有正确基本索引的字典中,然后是简单的数学运算,将剩余值添加到索引中。优点是在 Dictionary 添加方法中清楚地表明了您的限制。

于 2012-09-06T08:18:58.133 回答
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 回答
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 answer。这里需要注意的是,只有当您有大量对象要迭代时,性能影响才会变得明显,因此在我的应用程序中,我测试了 1000000 个项目(具有第 1、第 2 和第 3 属性的对象)。

只是为了让您了解 1000000 个项目的结果:

  • 您的原始代码和我上面的示例代码在大约 120 毫秒内执行
  • @mbm 和 @Steve 的答案(使用循环)都在大约 650 和 750 毫秒(分别)内执行。慢得多,慢得多!

我已将该程序的代码上传到 github > https://github.com/mouters/SO12295374_SpeedTest,因此请随时下载和测试。

于 2012-09-07T09:23:30.000 回答
-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 回答