处理数字范围

问题描述:

我需要返回一个值,该值与基于年龄的计算的某个权重相对应。处理数字范围

这里的年龄范围和权重: -

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

等(有没有真正的模式)

程序需要采取年龄作为输入,然后返回的权重(例如,如果年龄= 35,返回值是1.8。

这将如何做到最好?

我可以使用switch,但我不知道这是否是在最好的解决方法。是否还有一些其他的构造或技术可以在C#中应用,以实现这一点,如果权重发生变化,这将更加有效,便携/可扩展?

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

创建一个词典来定义您的年龄范围和权重。关键应与最小年龄和最大年龄此范围内的元组和值应该是你的体重:

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

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

您可以从表格,XML文件,数据库等内容创建该词典。

+0

字典在这里没有真正的帮助,因为你没有'Tuple'来进行查找。也可能是一个List >。 – juharr 2015-03-19 12:00:19

+0

@juharr嗯,我只是使用它是一个键/值集合的事实,枚举键的可能性。略微_simpler_使用比列表。 – DrKoch 2015-03-19 12:04:13

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

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

+0

忘了添加 - 我不能使用数据库表来实现这一点。对不起 - 忘了提及。 – 2015-03-19 11:39:54

如果因为他们似乎是在你的榜样范围是连续的,你只需要上限值,为了能够查询其排序的范围,所以你可以做这样的事情:

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"); 
    } 
} 

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

+0

在你的'RangeEntry'构造函数中''weight'参数应该是'float'而不是'int'。 – juharr 2015-03-19 12:15:30

+0

不错的地方!修订。 – 2015-03-19 13:01:42

不,据我所知,没有什么像范围结构。

你可以以这种方式使用的开关,或者说,如果范围总是从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) ... 

我不知道有什么更优雅的方法。

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

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。

如果范围不重叠,那么最好使用的是SortedList,其中键是范围的上限值,该值是权重。此外,您可以通过权重来区分未找到条目的情况。我添加了{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); 

您可以使用带复合键的字典,您将使用它来检查用户输入并获取匹配键的推荐值。

这里是例子;

 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  

希望它有助于..!

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

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

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