How would I search a range of ranged values using C#

后端 未结 8 2148
猫巷女王i
猫巷女王i 2021-02-10 20:49

I have a list of values like this

1000, 20400
22200, 24444

The ranges don\'t overlap.

What I want to do is have a c# function that can

8条回答
  •  情歌与酒
    2021-02-10 21:00

    As previously mentioned, if the set of ranges are big and non-overlapping, it is best to do a binary search. One way to do this is to use SortedDictionary, which implements a red-black tree to give a O(log(n)) search time. We can use the ranges as keys, and do a dictionary lookup by converting the single value we want to match into a range of a single point. If we implement the CompareTo method so that ranges that are overlapping are considered equal/matching, the dictionary lookup will find the matching range for use.

    public struct Range : IComparable
    {
        public int From;
        public int To;
    
        public Range(int point)
        {
            From = point;
            To = point;
        }
    
        public Range(int from, int to)
        {
            From = from;
            To = to;
        }
    
        public int CompareTo(Range other)
        {
            // If the ranges are overlapping, they are considered equal/matching
            if (From <= other.To && To >= other.From)
            {
                return 0;
            }
    
            // Since the ranges are not overlapping, we can compare either end
            return From.CompareTo(other.From);
        }
    }
    
    public class RangeDictionary
    {
        private static SortedDictionary _ranges = new SortedDictionary();
    
        public RangeDictionary()
        {
            _ranges.Add(new Range(1, 1000), "Alice");
            _ranges.Add(new Range(1001, 2000), "Bob");
            _ranges.Add(new Range(2001, 3000), "Carol");
        }
    
        public string Lookup(int key)
        {
            /* We convert the value we want to lookup into a range,
             * so it can be compared with the other ranges */
            var keyAsRange = new Range(key);
            string value;
            if (_ranges.TryGetValue(keyAsRange, out value))
            {
                return value;
            }
            return null;
        }
    }
    

    As an example, running the following code

    var ranges = new RangeDictionary();
    var value = ranges.Lookup(1356);
    

    value will in this case contain the string "Bob", since 1356 matches the range 1001-2000.

    In your case, if you are interested in fetching the range itself, you can use the range as both key and value in the dictionary. The example code can be easily extended to holding generic values instead.

    As a sidenote, this trick can also be done using a SortedList with virtually the same code, which uses less memory (array instead of tree) but have slower insertion/deletion time for unsorted data. They both use the default comparator for the key type (or a specified one) to compare values. The normal C# Dictionary on the other hand uses GetHashCode and Equals to compare values.

提交回复
热议问题