Фильтрация двух массивов для предотвращения значений Inf/NaN

У меня есть два массива, удваивается того же размера, containg значения X и Y для некоторых графиков.

Я должен создать некоторую защиту от значений INF/NaN. Я должен найти все это парами значений (X, Y), для которого оба, X и Y не являются INF, ни NaN

Если у меня есть один массив, я могу сделать это с помощью лямбд:

var filteredValues = someValues.Where(d=> !(double.IsNaN(d) || double.IsInfinity(d))).ToList();

Теперь, для двух массивов я использую следующий цикл:

List<double> filteredX=new List<double>();
List<double> filteredY=new List<double>();

for(int i=0;i<XValues.Count;i++)
{
   if(!double.IsNan(XValues[i]) &&
         !double.IsInfinity(XValues[i]) &&
         !double.IsNan(YValues[i]) &&
         !double.IsInfinity(YValues[i]) )
     {
       filteredX.Add(XValues[i]);
       filteredY.Add(YValues[i]);
     }
}

Существует ли способ отфильтровать два массива одновременно с помощью LINQ/lambdas, поскольку он был сделан для единого массива?

К сожалению, я могу использовать только.NET 3.5.

6
задан Peter Mortensen 17 June 2015 в 15:02
поделиться

5 ответов

Небольшая поправка к исходному ответу Марка:

var filteredValues = XValues.Zip(YValues, (x,y) => new { x, y })
        .Where(p => !(double.IsNan(p.x) || double.IsNan(p.y) || 
                      double.IsInfinity(p.x) || double.IsInfinity(p.y)))
        .ToList();

В качестве альтернативы , вы можете сделать его немного более аккуратным:

Func<double, bool> valid = z => !double.IsNan(z) && !double.IsInfinity(z);
var filteredValues = XValues.Zip(YValues, (x,y) => new { x, y })
        .Where(p => valid(p.x) && valid(p.y))
        .ToList();

Если затем вам нужно вернуть результаты в два списка, вы можете сделать:

var filteredX = filteredValues.Select(p => p.x).ToList();
var filteredY = filteredValues.Select(p => p.y).ToList();
6
ответ дан 10 December 2019 в 00:35
поделиться

В C# 4.0 появился метод расширения Enumerable.Zip для выполнения итерации по перечислимым "параллельно", как вы описали.

Сам я его не использовал, но это должно быть что-то вроде:

var filteredValues = 
   XValues.Zip(YValues, (x,y) => new { X = x, Y = y})
        .Where( o =>
          !(double.IsNan(o.X) || double.IsNan(o.Y) || double.IsInfinity(o.X) || double.IsInfinity(o.Y)))
            .ToList();

(Извините за смешные отступы, хотел, чтобы было более читабельно на SO)

2
ответ дан 10 December 2019 в 00:35
поделиться

Вы можете попробовать это сделать:

 doubleArray1.Zip (doubleArray2, (x, y) => Tuple.Create (x, y)) 
 .Where (tup =>! Double.IsNaN (tup.Item1) && 
! double.IsNaN (tup.Item2) && 
! double.IsInfinity (tup.Item1) && 
! double.IsInfinity (tup.Item1) ); 
 

В качестве альтернативы, вы можете создать метод для фильтрации и архивирования одновременно, главное преимущество состоит в том, что вы не ограничены C # 4:

 public static IEnumerable > DualWhere  (this IEnumerable  one, IEnumerable  two, Func  predicate) 
 {
var oneEnumerator = one. GetEnumerator (); 
var twoEnumerator = two.GetEnumerator (); 
while (oneEnumerator.MoveNext () && twoEnumerator.MoveNext ()) 
 {
if ( predicate (oneEnumerator.Current, twoEnumerator.Current)) 
yield return Tuple.Create (oneEnumerator.Current, twoEnumerator.Current); 
} 
oneEnumerator.Dispose (); {{ 1}} twoEnumerator.Dispose (); 
 
 

Изменить: Последний должен работать с C # 3.5 .

0
ответ дан 10 December 2019 в 00:35
поделиться

Хорошо, значит вы не можете использовать .NET 4.0 и поэтому не можете использовать расширение Zip.

Или можно?

public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(
    this IEnumerable<TFirst> first,
    IEnumerable<TSecond> second,
    Func<TFirst, TSecond, TResult> resultSelector)
{
    using (var eFirst = first.GetEnumerator())
    using (var eSecond = second.GetEnumerator())
    {
        while (eFirst.MoveNext() && eSecond.MoveNext())
            yield return resultSelector(eFirst.Current, eSecond.Current);
    }
}

Смотрите сами :)

static void Main(string[] args)
{
    var x = new double[] { 0.0, 1.0, 2.0, double.NaN, 4.0, 5.0 };
    var y = new double[] { 0.5, 1.5, double.PositiveInfinity, 3.5, 4.5, 5.5 };

    // note: using KeyValuePair<double, double> --
    // you could just as easily use your own custom type
    // (probably a simple struct)
    var zipped = x.Zip(y, (a, b) => new KeyValuePair<double, double>(a, b))
        .Where(kvp => IsValid(kvp.Key) && IsValid(kvp.Value))
        .ToList();

    foreach (var z in zipped)
        Console.WriteLine("X: {0}, Y: {1}", z.Key, z.Value);
}

static bool IsValid(double value)
{
    return !double.IsNaN(value) && !double.IsInfinity(value);
}

Выход:

X: 0, Y: 0.5
X: 1, Y: 1.5
X: 4, Y: 4.5
X: 5, Y: 5.5
2
ответ дан 10 December 2019 в 00:35
поделиться

Вот решение, которое будет работать в C# 3 и .NET 3.5

List<double> list1 = new List<double>() { 1.2, 3.8, double.NaN, 17.8 };
List<double> list2 = new List<double>() { 9.4, double.PositiveInfinity, 10.4, 26.2 };

var query = from x in list1.Select((item, idx) => new { item, idx })
            where !double.IsNaN(x.item) && !double.IsInfinity(x.item)
            join y in list2.Select((item, idx) => new { item, idx })
            on x.idx equals y.idx
            where !double.IsNaN(y.item) && !double.IsInfinity(y.item)
            select new { X = x.item, Y = y.item };

Итерация запроса даст пары, содержащие 1.2 & 9.4 и 17.8 & 26.2. Средние две пары будут отброшены, поскольку одна содержит NaN, а другая - бесконечность.

foreach (var pair in query)
{
    Console.WriteLine("{0}\t{1}", pair.X, pair.Y);
}
0
ответ дан 10 December 2019 в 00:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: