处理数字范围

时间:2015-03-19 11:34:37

标签: c# oop

我需要返回一个值,该值对应于基于年龄的计算的某些加权。

这里是年龄范围和体重: -

21-30: 1.2
31-40: 1.8
41-50: 1.9

等等(没有真正的模式)

程序需要输入年龄作为输入,然后返回加权(例如,如果年龄= 35,则返回值为1.8。

如何最好地实现这一目标?

我可以使用switch,但我不确定它是否是解决此问题的最佳方法。我是否可以在C#中应用其他一些构造或技术来实现这一目标,如果权重发生变化,这将更有效,更便携/可扩展?

另一件事 - 我无法使用数据库来存储任何权重数据 - 只需将其添加到信息中即可。

8 个答案:

答案 0 :(得分:1)

创建字典以定义年龄范围和权重。关键应该是具有此范围的最小年龄和最大年龄的元组,值应该是您的体重:

Dictionary<Tuple<int,int>, double>  // minAge, MaxAge -> weight

然后你可以遍历所有按键来找到你的体重。

您可以根据表格,XML文件,数据库等内容创建此字典。

答案 1 :(得分:1)

我们在这里的系统中做了类似的事情,我们使用在数据库表中存储加权和下限的概念。因此,我们需要做的就是找到阈值最小值低于输入值的记录并读取权重。

这简化了流程,并允许编辑,添加和删除值。

答案 2 :(得分:1)

如果范围是连续的,因为它们似乎在您的示例中,您只需要将上限值和范围排序以便能够查询它,因此您可以执行以下操作:

public class RangeEntry
{
    public RangeEntry(int upperValue, float weight)
    {
        UpperValue = uperValue;
        Weight = weight;
    }

    public int UpperValue { get; set; }
    public float Weight { get; set; }
}

public class RangeWeights
{
    private List<RangeEntry> _ranges = new List<RangeEntry>
    {
        new RangeEntry(30, 1.2f),
        new RangeEntry(40, 1.8f),
        new RangeEntry(50, 1.9f),
    }

    public float GetWeight(int value)
    {
        // If you pre-sort the ranges then you won't need the below OrderBy
        foreach (var r in _ranges.OrderBy(o => o.UpperValue)) 
        {
            if (value <= r.UpperValue)
                return r.Weight;
        }

        // Range not found, do whatever you want here
        throw new InvalidOperationException("value not within in any valid range");
    }
}

这种方法的价值在于添加新范围意味着在范围的实例化中只添加一行代码。

答案 3 :(得分:1)

如果范围不重叠,那么最好使用的是SortedList,其中键是范围的上限值,值是权重。此外,您可以使weigth为空,以区分未找到条目的情况。我添加了{20, null}的条目,这样如果年龄<= 20,您将获得null而不是1.2。

var rangedWeights = new SortedList<int, float?>
{
     { 20, null }
     { 30, 1.2f }, 
     { 40, 1.8f }, 
     { 50, 1.9f }
};

int age = 44;
float? weight = null;
foreach (var kvp in rangedWeights)
{
    if (age <= kvp.Key)
    {
        weight = kvp.Value;
        break;
    }
}

您可以动态添加新条目,但仍然可以确保它们已排序。

rangedWeights.Add(60, 2.1f);

答案 4 :(得分:1)

您可以将词典与复合键一起使用,您将使用该词来检查用户输入并获取匹配键的值。

以下是示例;

        Dictionary<Tuple<int, int>, double> t = new Dictionary<Tuple<int, int>, double>();

        t.Add(new Tuple<int,int>(11,20),1f);
        t.Add(new Tuple<int, int>(21, 30), 2f);
        t.Add(new Tuple<int, int>(31, 40), 3f);

        int weight = 34;

        double rr = (from d in t where d.Key.Item1 <= weight && d.Key.Item2 >= weight select d.Value).FirstOrDefault();

        Console.WriteLine(rr);  // rr will print 3.0    

希望它有所帮助.. !!

答案 5 :(得分:1)

如果您正在寻找更短的写作方式,我建议您使用?: operator

double getWeight(int age){
    return (age <= 30) ? 1.2 :
           (age <= 40) ? 1.8 : 1.9;
} 

与使用开关相同。只有更短的方式。如果您不希望它们被硬编码,您可以用变量替换数字和权重。

答案 6 :(得分:0)

不,据我所知,没有像范围结构那样的东西。

如果范围始终从x1到y0

,您可以使用这种方式的开关
switch((value-1) / 10)
{
    case 1: ... break; 
    case 2: ... break;
}

或者,如果需要:

switch(value)
{
    case 11:
    case 12:
    case 20: ... break;
    case 21: ... 
}

根据您需要的群组数量,您可以执行

等检查
if(value > 10 && <= 20) ...

我不知道更优雅的方法。

答案 7 :(得分:0)

不清楚年龄范围和体重数据的结构是什么, 但我可能会这样做:

Class AgeRangeAndWeight {
   int FromAge {get;set;}
   int ToAge {get;set;}
   double Weight {get;set;}
}

Class AgeRangeAndWeight Collection() : List<AgeRangeAndWeight> {
  AgeRangeAndWeight FindByAge(int age) {
    foreach(AgeRangeAndWeight araw in this) {
      if(age >= araw.FromAge && age <= araw.ToAge) {
        return araw;
      }
    }
  return null;
  }
}

然后你要做的就是调用FindByAge方法。记得检查它是否没有返回null。