curiousUser
curiousUser

Reputation: 7

C# Get index from List where value is in a range

Let's say I have a List<float> with the following values:

{20, 60, 80, 85, 90, 120, 140}

And I have one number, let's suppose "75". How can I find the index where this number I have (75) is >= then an index's value and < then the next index's value? In basic words, I want to find that my number (75), is "inside" the range between 60 and 80, so it returns to me index number 1.

So far, I've used Linq but it only returns to me the nearest value. I'd like to find the Index instead.

myList.OrderBy(x => Math.Abs(points - x)).First()

Is there an efficient way to return to me this index? I know there's the possibility to use a For loop, but I believe that a loop may be heavy if I take into consideration that I may have to call this a couple of times in a few seconds. (The list will contain ~99 values).

Thank you very much! I appreciate any help!

Upvotes: 0

Views: 1504

Answers (5)

mshsayem
mshsayem

Reputation: 18008

Actually, a for loop will be fast. The accepted answer has an OrderBy (has time complexity of nlogn), but assuming your list is already sorted, and you can try this:

var myList = new List<float>{20, 60, 80, 85, 90, 120, 140};
var numberToSearch = 75;
var foundIndex = -1;

for(var i=0; i<myList.Count; i++)
{
    if(myList[i] >= numberToSearch)
    {
        foundIndex = i;
        break;
    }
}

if(foundIndex<=0)
{
    // Element was not found
}
else
{
    // the desired range is: [foundIndex-1, foundIndex], i.e. (1,2)
}

Upvotes: 1

Anu Viswan
Anu Viswan

Reputation: 18155

I hope I understood what you meant.

Following should help you

var list = new List<float>{20, 60, 80, 85, 90, 120, 140};
var numberToSearch = 70;
var result = list.Select((x,index)=> new 
                                     {
                                       Index=index, 
                                       Value=x, 
                                       Diff = Math.Abs(x-numberToSearch)
                                     })
                 .OrderBy(x=>x.Diff)
                 .First()
                 .Index;
Console.WriteLine($"Search Term {numberToSearch}, Index={result}");

Alternatively (if the list is sorted initially), you could also do

var result = list.Select((x,index)=> new {number=x, index= index}).First(x=> x.number > numberToSearch).index - 1;

if(result == -1)
{
    Console.WriteLine("Not Found");
}
else
    Console.WriteLine($"Search Term {numberToSearch}, Index={result}");
}

Output for numberToSearch = 70

Search Term 70, Index=1

Output for numberToSearch = 87

Search Term 87, Index=3

Upvotes: 2

Moshi
Moshi

Reputation: 1423

Answer from @mshsayem is correct but much nicer code will be

        var list = new List<float>{20, 60, 80, 85, 90, 120, 140};
        var numberToSearch = 70;
        var foundIndex = myList.FindIndex(_ => _ > numberToSearch);
        if (foundIndex < 0) // not found;
        if(foundIndex == 0) // found but first element
        else // index foundIndex-1 and foundIndex

It will not check further elements when getting hit.

Upvotes: 0

Pophoff
Pophoff

Reputation: 1

I would try a method that looks at the first number (20), if it is not greater than 75, it puts 20 in a method and it moves onto the next number (40), since it is not greater than 75 it replaces the method that stores 20, with the number 40, then it moves onto the next number, that should happen until it reaches 80. Once it reaches 80, then It should read that 80 is greater than 75. Then take the method that stores the number before it, which would be 60, and it would put 75 in between them.

Upvotes: 0

sam
sam

Reputation: 1985

Since your collection is of primitive type, you can use IndexOf of List collection.Please try this:

myList.IndexOf(myList.Where(f => f.x >= points).OrderBy(f => f).First())

Upvotes: 0

Related Questions