2016-08-12 47 views
2

我目前正在通过以下方式查找列表的上限和下限之间的值

int testValue = 180000; 

List<TaxBracket> taxes = new List<TaxBracket>(); 
taxes.Add(new TaxBracket(18199, 0)); //0 to 18199 
taxes.Add(new TaxBracket(36999, 19)); //18200 to 36999 
taxes.Add(new TaxBracket(79999, Convert.ToDecimal(32.50D))); //37000 to 79999 
taxes.Add(new TaxBracket(179999, 37)); //80000 to 179999 
taxes.Add(new TaxBracket(180000, 47)); //180000 

decimal result = taxes[taxes.Count-1].Value; 

for (int i = 0; i < taxes.Count; i++) 
{ 
    if (i == 0) 
    { 
     if (testValue < taxes[i].Limit) 
      result = 0; 
    } 

    if (i > 0) 
    { 
     if (testValue < taxes[i].Limit && testValue > taxes[i - 1].Limit) 
     { 
      result = taxes[i].Value; 
     } 
    } 
} 

Console.WriteLine(result); 

计算税率是否有LINQ任何替代做到这一点,而不是使用这种老派的做法?看起来非常接近this,但有点不同。

+0

你能告诉我的逻辑:TaxBracket(36999,19))如何';'会'18200至36999' ,'18200'是从哪里来的? –

+0

@不幸运 - 集合中的每个项目都是范围的顶部数字。所以第0项是用于所有的值,直到限制 - 这是18199 –

+0

尝试以下解决方案,如果值大于表值,将返回null:decimal? result = taxes.Where(x => testValue x.Value).LastOrDefault(); – jdweng

回答

4

如果我理解正确的,这是你想要什么:

var result = taxes.OrderBy(item => item.Limit) 
        .SkipWhile(item => item.Limit < testValue) 
        .FirstOrDefault()?.Value; 

它会为了您的收藏从最小Limit到最大,然后将Skip,直到达到Limit比你testValue等于或大于。因为集合是有序的,所以FirstOrDefault它是有价值的。

或者:

var result = taxes.Where(item => item.Limit >= testValue) 
        .OrderBy(item => item.Limit) 
        .FirstOrDefault()?.Value; 

这样着眼于从不同的方向的问题。只拿到等于或等于testValue的物品,然后命令他们采取第一个。

3

作为LINQ的替代我建议使用二进制搜索,提供taxes排序:

int index = taxes.BinarySearch(
    new TaxBracket(testValue, -1), // -1: this parameter is ignored 
    Comparer<TaxBracket>.Create((left, right) => left.Limit.CompareTo(right.Limit))); 

if (index < 0) 
    index = ~index - 1; // in between of two indexes 

var result = taxes[index].Value; 

二进制搜索时,你名单的工作可能是有用的(算法确保O(log(N))复杂,当时Linq提供O(N)一);但是当taxes小,的LINQSkipWhile(见吉拉德格林的答案)是更具可读性

+0

与@Gilad Green建议的方法相比,这有点好吗? – 3615

+0

@ 3615 - 我会说,在较小的集合的性能并不重要,但在大型的这是更有效率:) –

+0

@Dmitry - 尼斯方法 –