How do we find very first closest value from the list of values linq C#

BeUnique 2,112 Reputation points
2020-11-27T04:34:11.17+00:00

I have the list of values. like below.

I am struggling to get very first closest values from the list. How do we get this...?

For example, i have the list below.

list<double> data1 = {1000, 2000, 3000, 4000, 100, 350, 600, 800, 200, 300, 400, 500, 10. 20, 30, 40,100000, 200000, 300000 }

passing number : "420"

so the searching should happen in between 350 and 600 and result should come as "350". if this value is not there in the list, then only it should goto "400"

How do we form the logic..?

C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,640 questions
0 comments No comments
{count} votes

Accepted answer
  1. Timon Yang-MSFT 9,586 Reputation points
    2020-11-30T07:30:52.347+00:00

    I seem to understand what you mean.

    I think you are not trying to find the number that is closest to 420 among all the numbers, but to find the first group containing 420.

    For 420, it is 350 and 600. For other numbers such as 610, it is 600 and 800.

    Then find the closest number from these two numbers, if there is no such set of numbers that meet the requirements, then look for the true closest number.

    If my guess is correct, please try the following code:

            public static double SearchArray(double inValToSearch_, List<double> inArr_)  
            {  
                if (inArr_ == null || inArr_.Count == 0)  
                    return 0;  
                for (int i = 0; i < inArr_.Count-1; i++)  
                {  
                    if (inArr_[i] < inValToSearch_ && inArr_[i+1] > inValToSearch_)  
                    {  
                        return inValToSearch_ - inArr_[i] < inArr_[i + 1] - inValToSearch_ ? inArr_[i] : inArr_[i+1];  
                    }  
                }  
      
                return inArr_.OrderBy(item => Math.Abs(inValToSearch_ - item)).First();  
            }  
    

    If the response is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    0 comments No comments

3 additional answers

Sort by: Most helpful
  1. Cheong00 3,476 Reputation points
    2020-11-27T06:03:54.14+00:00

    Something like this?

     List<double> data1 = new List<double>(){1000, 2000, 3000, 4000, 100, 350, 600, 800, 200, 300, 400, 500, 10, 20, 30, 40,100000, 200000, 300000 };
     double input = 420;
     var diffList = data1.Select(x => new { n = x, diff = Math.Abs(x - input) });
     var result = diffList.Where(x => x.diff == diffList.Select(y => y.diff).Min()).First();
     Console.WriteLine(result.n);
    

    Btw, I don't really understand your criteria to select 350 instead of 400. If you want "the first number close enough to the input number", you need to define what is "close enough", say "within ?% value difference from the input number" or some absolute difference value.

    After you make up your mind you can modify the "x.diff == diffList.Select(y => y.diff).Min()" to "x.diff <= [some value]" to suit your need.

    1 person found this answer helpful.

  2. BeUnique 2,112 Reputation points
    2020-11-27T08:01:08.637+00:00
    **Complete source code below**  
      
         Excel.Application xlApp = new Excel.Application();  
                    Workbook xlWorkbook = xlApp.Workbooks.Open(@"C:\Project\Test\testExcel.xlsx");  
                    Worksheet sheet = xlWorkbook.ActiveSheet;  
                    try  
                    {  
                        int startRow = 1;  
                        char startColumn = 'A';  
                        int endRow = 4;  
                        char endColumn = 'E';  
                        int num = 420;  
          
                        int intStartY = (int)startColumn - 64;  
                        int intEndY = (int)endColumn - 64;  
                        //object[,] data = sheet.Range[sheet.Cells[startRow, startColumn.ToString()], sheet.Cells[endRow, endColumn.ToString()]].Cells.Value2; // checking row wise  
          
                        List<double> data1 = new List<double>();  
                        for (int j = intStartY; j <= intEndY; j++)  
                        {  
                            for (int i = startRow; i <= endRow; i++)  
                            {  
                                if (sheet.Cells[i, j].Value != null)  
                                {  
                                    data1.Add(Convert.ToDouble(sheet.Cells[i, j].Value));  
                                     
          
                                }  
                            }  
                        }  
          
                       double closest = SearchArray(num, data1);  
                        Console.WriteLine(closest);  
          
          
          public static double SearchArray(double inValToSearch_, List<double> inArr_)  
                {  
                    if (inArr_ == null || inArr_.Count == 0)  
                        return 0;  
                    var re = inArr_.OrderBy(item => Math.Abs(inValToSearch_ - item));  
                    return re.First();  
                }  
      
      
      [1]: /api/attachments/43126-search-array-data-1.png?platform=QnA  
      
      
      
    

  3. Andrea Angella 171 Reputation points
    2020-11-28T10:15:36.013+00:00

    Hi @Ganesh Sunkara , unfortunately, your requirements are unclear so we can't help with a direct solution. You need to sit with the problem and understand what you want exactly.

    This is my main advice.

    If you need to create logic that analyzes adjacent pairs of numbers, don't be afraid to use classic for loops. You don't have to find a LINQ version of your code every time. Use the language feature that helps you to make your code more readable.

    The following code returns the minimum value of the first range in the list that contains your search value.

    double FindClosest(List<double> data, double value)  
    {  
        for (var i = 0; i < data.Count - 1; i++)  
            if (data[i] <= value && value <= data[i + 1])  
                return data[i];  
      
        return data.Last();  
    }