0

Can anyone help me ?

for C#

I need to implement a routine that tests if a point is within a range ( array ), C#

in the figure below the ranges are [1-3],[6-9], [11-15]

i would like to use something like binarysearch, i used it but there is a flaw, because it can only test 2 ranges in this case ... if i have 2 ranges, the binarysearch works well because gives the 2 events in the IComparer for the 2 ranges. ([1-3],[6-9])

after i add 3 ranges the binarysearch only give me 2 ranges, [6-9], [11-15]

I'm using List<Tuple<int, int>> range, and IComparer<Tuple<int, int>>

something like that ---

class RangeComparerPoint : IComparer<Tuple<int, int>>
    {
        public int Compare(Tuple<int, int> f1, Tuple<int, int> f2)
        {
            //for the sake of clarity
            int boundary_1 = f1.Item1;
            int boundary_2 = f1.Item2;
            int pos = f2.Item1;
            int currPos = f2.Item2;

            //EndSection 
            if (pos > currPos)
            {
                if (pos >= boundary_1 && currPos < boundary_1)
                {
                    //in the range
                    return 0;
                }
            }
            else
            {
                if ( boundary_1 > currPos )
                {
                    return -1;
                }

                if (pos <= boundary_1)
                {
                    //in the range
                    return 0;
                }
            }
            return -1;
        }
    }

enter image description here

cealex
  • 173
  • 7

1 Answers1

0

You need to be a bit more precise in framing the problem...

  1. Ranges may not overlap (or implement logic to consolidate them)
  2. Ranges are all closed intervals i.e. [1..3] means 1 <= x <= 3
    and you do not cater for (say) [1..4) meaning 1 <= x < 4
  3. Integers only etc.

Going with these as assumptions and a bit of a kludge that requires you to search for Tuple<a,a> for the value a (see exception in Comp() method), here's an example of how to achieve what you're after...

using System;
using System.Collections;
using System.Collections.Generic;

namespace ConsoleApp2
{
  class Program
  {
    // x represents a point and y a range 
    // (params are swapped if necessary, i.e. if y is a point and x a range)
    // returns 0 if x falls within the range represented by y
    // returns -1 if x falls before y on the number line, +1 if it falls after y
    public static int Comp(Tuple<int, int> x, Tuple<int, int> y)
    {
      var fSwap = 1;
      if (x.Item1 != x.Item2) 
      {
        (x, y) = (y, x); // swap so that x is always the value being searched for
        fSwap = -1;
      }
      if (x.Item1 != x.Item2) // ***
        throw new Exception("The value being sought MUST be new Tuple(a,b) where a == b");
      return fSwap * (x.Item1 < y.Item1 ? -1 : x.Item1 > y.Item2 ? +1 : 0);
    }

    static void Main(string[] args)
    {
      // must be non-overlapping and increasing
      var ranges = new List<Tuple<int, int>>
      {
        new Tuple<int, int>(1, 3),
        new Tuple<int, int>(6, 9),
        new Tuple<int, int>(11,15)
      };

      for (int i = 0; i < 20; i++)
      {
        var foundIn = ranges.BinarySearch(new Tuple<int, int>(i, i), Comparer<Tuple<int, int>>.Create(Comp));
        if (foundIn < 0)
          Console.WriteLine($"{i} does not fall in any range");
        else
          Console.WriteLine($"{i} falls within [{ranges[foundIn].Item1},{ranges[foundIn].Item2}]");
      }
      Console.ReadKey();
    }
  }
}

Giving result...

0 does not fall in any range
1 falls within [1,3]
2 falls within [1,3]
3 falls within [1,3]
4 does not fall in any range
5 does not fall in any range
6 falls within [6,9]
7 falls within [6,9]
8 falls within [6,9]
9 falls within [6,9]
10 does not fall in any range
11 falls within [11,15]
12 falls within [11,15]
13 falls within [11,15]
14 falls within [11,15]
15 falls within [11,15]
16 does not fall in any range
17 does not fall in any range
18 does not fall in any range
19 does not fall in any range
AlanK
  • 1,827
  • 13
  • 16
  • Hy, Ranges not overlap. i've already implemented with BinarySearch, and works perfectly with 2 ranges, when i add one more range, the binarysearch only give me 2 ranges, [6-9], [11-15], but i need to inspect the [1-3] range. Yes it's only integers!. in the pratics i need some function which returns all ranges in a comprable method to verify the point ... – cealex Jan 30 '22 at 15:30
  • i updated the post with more info, RangeComparerPoint. tomorrow i'll test your code, it's not what i wanted , but it seems easily to implement and not so complicated ... thank you for your effort ! – cealex Jan 30 '22 at 15:42
  • I suspect you have not understood the purpose of `IComparer` (without seeing how you use it, it is difficult to diagnose the misunderstanding). `IComparer.Compare()` compares any two instances of T (here `Tuple`) and an ordered collection (in my example `List`) uses its `BinarySearch()` which uses the provided `IComparer.Compare()`. (This is why I drew attention to the kludge in my example.) If you are coding binary search in a method of your own then don't use `IComparer` at all. What you need is a `Compare(Tuple, int)` method. – AlanK Jan 30 '22 at 16:32
  • It would also be fair to credit the answer since it did address the question asked (unless someone else posts a better one;-). – AlanK Jan 30 '22 at 16:35
  • what i need is something that triggers an event for each range , event1 = [2-3] , event2= [6-9] , event3=[11-15] obviously the problem is more complex , and i need to test the boundaries. this is about drag and drop items in a list on a webpage , and you can drag and drop from many directions, left to right and vice-versa but certain moves are not permitted, neither overlap ... i started to develop with binary search and works well for 2 rangs, as i said before, i never used the binary search before. – cealex Jan 30 '22 at 23:02
  • After the code was done for 2 range, i tested with 3 ranges and doesn't work , so now i do not want to waste more time developing another approach and i'm trying to reuse the same code with minimum changes .. – cealex Jan 30 '22 at 23:03
  • i found the solution , instead of calling int res = range.BinarySearch(new Tuple(targetPosition, currentPosition), new RangeComparer()); i did for (int i = 0; i < range.Count(); i++) { res = range.BinarySearch(i, 1, new Tuple ..., and was able to get all ranges. your solution gave me the idea – cealex Jan 31 '22 at 11:52
  • You've missed the point of BinarySearch which promises to locate an item in an ordered list containing n entries within log(n) iterations (256 entries takes up to 8 iterations, 1024 entries 10 iterations etc). You are now checking 1 entry at a time for n iterations (linear search) using BinarySearch on sub-lists of length 1. Don't mix methods, choose linear or binary based on likely list length, unless this can grow large (>~50) there's no need for BinarySearch; just scan linearly `for (int i = 0; i < range.Count(); i++) bool found = searchValue >= range.Item1 && searchValue <= range.Item2;`. – AlanK Feb 01 '22 at 04:49
  • My answer shows how `List.BinarySearch()` might be used but it would be both unnecessarily complex and expensive (slow) for short lists. If performance is a critical issue you must do some benchmarking but as a guide I'd recommend you don't consider binary search for 20 ranges or less and don't consider linear for >100. – AlanK Feb 01 '22 at 05:01