【问题标题】:Best way to find values in range在范围内查找值的最佳方法
【发布时间】:2012-02-02 23:18:31
【问题描述】:

我有一组值:

  • [0-20] = 1
  • [21-30] = 2
  • [31-40] = 3 等

例如,我希望来自 [44] 中的用户的输入。确定价值落在哪个项目中的最有说服力的方法是什么?

我可以编写一个 switch 语句来匹配 case >

更新

我正在寻找一种简洁的方法来查找用户输入的范围,例如使用 LAMDBA:

List<int>().Find(x => x.WithinRange(range))

或者类似的东西。

【问题讨论】:

  • 我不确定您在寻找什么......
  • 你是说你有一个“最小/最大”值的集合吗?
  • if 语句很好:简单、有效且易于理解。
  • @CodingGorilla 是的,我有最小值/最大值
  • 您需要速度吗?如果是这样,那么一个庞大的字典将是最快的方法,无论如何我认为没有充分的理由浪费这么多内存并使代码更难阅读以获得如此小的性能提升

标签: c#


【解决方案1】:

如果您的范围是连续的,如您的示例(即没有间隙),您可以将它们的端点存储在一个数组中,如下所示:

var endpoints = new[] {20, 30, 40, 60, 90};

请注意,端点已排序。您现在可以使用binary search 方法在此数组中查找 44 的插入点,即 3,将返回(二进制搜索将返回 3 的按位补码;您需要应用 ~ 才能获得实际值)。

【讨论】:

    【解决方案2】:

    你去吧:

    int GetRange(int value) 
    { 
        return (value > 30) ? 3 :
               (value > 20) ? 2 :
               (value > 0)  ? 1 :
               0;
    }
    

    没有如果!

    【讨论】:

      【解决方案3】:

      类似这样的扩展:

      public static int WithinRange(this int value)
      {
          if (value < 0) return 0;
          if (value < 21) return 1;
          return (value - 1) / 10;
      }
      

      没有if 语句

      public static int WithinRange(this int value)
      {
          return (value < 0) ? 0 
              : (value < 21) ? 1 
              : (value - 1) / 10;
      }
      

      用法:

      collection.Find(x => x.WithinRange(range)) 
      

      【讨论】:

      • 类似这样,但不使用 IF 语句:$
      • if 语句没有问题,我只是好奇在给定的最小/最大范围内找到值的其他方法
      • 不确定是否可以避免 if 语句,因为您的第一个 0-20 案例不适合其他模式
      【解决方案4】:

      只需遍历范围并查看值是否在范围内...

      var ranges = new[]
      {
          Tuple.Create(0, 20),
          Tuple.Create(21, 30),
          Tuple.Create(31, 40),
          Tuple.Create(41, 50),
          // ...
      };
      var number = 44;
      for (int i = 0; i < ranges.Length; i++)
      {
          var range = ranges[i];
          if (number >= range.Item1 && number <= range.Item2)
          {
              var theIndex = i + 1;
              // do something with theIndex
          }
      }
      

      【讨论】:

        【解决方案5】:

        你可以操纵输入:

        int input = //Whatever the input is
        int index = (input-1)/10;
        

        假设整数输入,并且您的数组已按指示进行索引。

        【讨论】:

          【解决方案6】:

          @Jeff Mercado 回答的效率较低的 .NET 3.5 替代变体:

          var ranges = new[]
          {
              Enumerable.Range(0, 20),
              Enumerable.Range(21, 30),
              Enumerable.Range(31, 40),
              Enumerable.Range(41, 50),
              // ...
          };
          var number = 44;
          for (int i = 0; i < ranges.Length; i++)
          {
              var range = ranges[i];
              if (range.Contains(number))
              {
                  var theIndex = i + 1;
                  // do something with theIndex
              }
          }
          

          【讨论】:

            【解决方案7】:

            更新:我知道这有点矫枉过正,但它可能会给你一些想法。我不明白,你已经知道如何解决这个问题,但你只是在寻找一个“更漂亮”的解决方案:

            public class Range
            {
                public int Left { get; set; }   
                public int Right { get; set; }
                public string Title { get; set; }
            
                public Range(int left, int right, string title) { Left = left; Right = right; Title = title; }
            
                public bool Contains(int x) { return Left <= x && x <= Right; }
            }
            
            void Main()
            {
                var x = 15;
            
                var ranges = new[] {
                    new Range(0, 10, "A"),
                    new Range(11, 20, "B")
                };
            
                var foo = ranges.Where(r => r.Contains(x)).Single();
            
                Console.Write(foo.Title);
            }
            

            我之前的建议For 声明没问题,但我更喜欢 LINQ :)

            var x = 15;
            
            var ranges = new[] { Tuple.Create(0, 10), Tuple.Create(11, 20) };
            var range = ranges.Where(r => r.Item1 <= x && r.Item2 >= x );
            
            Console.Write(range.Item1);
            Console.Write(range.Item2);
            

            【讨论】:

            • 元组是 4.0 特定的,应该提到我在一个 3.5 项目中。但是感谢所有反馈的家伙,非常感谢这个论坛的专业知识。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2018-10-19
            • 1970-01-01
            • 2019-01-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多