Ikram Khan
Ikram Khan

Reputation: 73

find nearest number in list of float

hi there i have an list of float

       List<float> distance = new List<float>();
        distance.Add(66.2F);
        distance.Add(69.9F);
        distance.Add(70.2F);
        distance.Add(70.3F);
        distance.Add(70.6F);
        distance.Add(71.4F);
        distance.Add(71.6F);

i have a extension method which get nearest number from this array

 public static class extenstions
{
    public static float ClosestTo(this IEnumerable<float> collection, float target)
    {

        var closest = float.MaxValue;
        var minDifference = float.MaxValue;
        foreach (var element in collection)
        {
            var difference = Math.Abs((long)element - target);
            if (minDifference > difference)
            {
                minDifference = (int)difference;
                closest = element;
            }
        }

        return closest;
    }
}

float closest = distance.ClosestTo(70F); now if i want to find nearest of number 70 it will return 70.2 what i want is to modify this function to return less closest 69.9 instead of higher value 70.2. can you help?

Upvotes: 0

Views: 3489

Answers (3)

Thomas Levesque
Thomas Levesque

Reputation: 292465

Using Linq:

public static float ClosestTo(this IEnumerable<float> collection, float target)
{
    return collection.OrderBy(x => Math.Abs(target - x)).First();
}

Or, using the MinBy extension method from Linq.Extras:

public static float ClosestTo(this IEnumerable<float> collection, float target)
{
    return collection.MinBy(x => Math.Abs(target - x));
}

It's better than using OrderBy because it runs in O(n) instead of O(n log n).


EDIT: if two numbers are equally close to the target and you want the greater of the two, you can do this:

public static float ClosestTo(this IEnumerable<float> collection, float target)
{
    return collection
        .OrderBy(x => Math.Abs(target - x))
        .ThenByDescending(x => x)
        .First();
}

Upvotes: 4

Aht
Aht

Reputation: 593

Probably when u cast value to long u lose number after coma 70,2 -> 70 and 69,9 -> 69 and 70 is closest to 70 than 69

If u want to take closest from left or right use this :

    public static float ClosestTo(this IEnumerable<float> collection, float target)
    {
        float a = collection.Where(x => x >= target).OrderBy(x => x - target).First();
        float b = collection.Where(x => x < target).OrderBy(x => Math.Abs(target - x)).First();
        return a.Equals(b) ? a : Math.Min(a, b);
    }

where a is right and b is left ( if u wanna left change return a.Equals(b) ? a : Math.Min(a, b); to return a.Equals(b) ? b : Math.Min(a, b);

Upvotes: 2

Dexion
Dexion

Reputation: 1101

Do not cast the element variable to long.

Upvotes: 1

Related Questions