Frage

I have an IEnumerable<float> containing distinct values found in a three dimensional array.

Given a test value, I want to take two elements from my distinct IEnumerable, the closest value which is greater than or equal to the test value, and the closest value which is less than the test.

In other words, if my test value is 80.5, and my list contains:

  • 1.0
  • 1.65
  • 2.345
  • 99.439

Then I want an IEnumerable<float> or a Tuple<float,float> back which contains 2.345 and 99.439.

Is there a LINQ statement or combination of such which will do that? An approach without LINQ?

War es hilfreich?

Lösung

Without using LINQ and assuming that there are only values > 0 in an input collection. There's no need to sort the collection first.

public Tuple<float, float> GetClosestValues(IEnumerable<float> values, float target)
{
    float lower = 0;
    float upper = Single.MaxValue;
    foreach (var v in values)
    {
        if (v < target && v > lower) lower = v;
        if (v > target && v < upper) upper = v;
    }

    return Tuple.Create(lower, upper);
}

Andere Tipps

In a tuple:

var t = Tuple.Create(list.Where(x => x <= value).Max(),
                     list.Where(x => x >= value).Min()
                    );

Although you don't state what the output should be if the value is in the list - in this case it would be a tuple with the same value for both "nodes"

Tuple.Create(
    values.OrderBy(i => i)
          .SkipWhile(i => i < test)
          .FirstOrDefault(),
    values.OrderByDescending(i => i)
          .SkipWhile(i => i >= test)
          .FirstOrDefault());
  1. Sort (ascending), skip all values less than test, take the first value greater than or equal to test.
  2. Sort (descending), skip all values greater than or equal to test, take the first value less than test.
double[] data = { .1,5.34,3.0,5.6 };
double test = 4.0;

var result = data.Aggregate(Tuple.Create(double.MinValue, double.MaxValue), 
(minMax, x) => Tuple.Create(
    x < test && x > minMax.Item1 ? x : minMax.Item1,
    x >= test && x < minMax.Item2 ? x : minMax.Item2));

Assuming your list is sorted (and few other assumptions on the requirements (such as what happens if there is a direct hit).

float prev=0;
foreach(float item in YourIEnumerableFloatVar)
{
   if (item > target)
   {
       return new Tuple<float, float> (prev, item);
   }

   prev = item;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top