2010-05-07 16 views
5

Tengo dos matrices de dobles del mismo tamaño, con valores X e Y para algunos gráficos.Filtrar dos matrices para evitar valores de Inf/NaN

Necesito crear algún tipo de protección contra los valores INF/NaN. Necesito encontrar todo lo que los pares de valores (X, Y) para los que ambos, X e Y no están INF ni NaN

Si tengo una matriz, que pueden hacer que el uso de lambdas:

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

ahora, para los dos conjuntos utilizo el siguiente bucle:

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]); 
    } 
} 

¿hay una manera de filtrar dos matrices al mismo tiempo utilizando LINQ/lambdas, como se hizo para la única matriz?

Lamentablemente solo puedo usar .NET 3.5.

+0

ligero error en su declaración. filteredX se declara dos veces. Estoy seguro de que quisiste decir "filtrado" para uno de ellos. : D –

+0

¡Gracias! :) Editado. – Gacek

+0

Lo que buscas es bastante factible en .NET 3.5. Ver mi respuesta –

Respuesta

5

corrección leve de Marcos respuesta original:

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(); 

Alternativamente, es posible que desee para que sea un poco más ordenado:

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(); 

Si este caso es necesario, devuelve los resultados en dos listas, que puede hacer:

var filteredX = filteredValues.Select(p => p.x).ToList(); 
var filteredY = filteredValues.Select(p => p.y).ToList(); 
+0

Supongo que debe haber IsInfinity en lugar de segundo IsNan en su declaración válida de Func? Lamentablemente no puedo usar 4.0 (ver edición), pero gracias de todos modos – Gacek

+0

@Gacek: Sí, debería ser IsInfinity; fijo. También puede obtener el operador Zip de MoreLINQ: http://morelinq.googlecode.com –

+0

Gracias, probablemente lo haga. Gracias por tu ayuda. – Gacek

2

C# 4.0 introduce el método de extensión Enumerable.Zip para realizar iteraciones sobre enumerables "en paralelo", como usted describe.

No he utilizado yo mismo, pero debería ser algo como:

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(); 

(Lo siento por la sangría divertido, quería que fuera más fácil de leer en SO)

+1

Zip no tiene predicado, solo una lambda que convierte xey en un solo valor. – Rubys

+0

Bueno. Desearía poder usar 4.0 (lo siento, olvidé escribirlo en mi pregunta). – Gacek

+0

@Gacek: ¡Nada le impide escribir su * extensión * 'Zip'! Ver mi respuesta;) –

0

se puede tratar de hacer esto:

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)); 

Alternativamente, se puede hacer una método para filtrar y comprimir al mismo tiempo, la principal ventaja es que no está limitado a C# 4:

public static IEnumerable<Tuple<TOne, TTwo>> DualWhere<TOne, TTwo>(this IEnumerable<TOne> one, IEnumerable<TTwo> two, Func<TOne, TTwo, bool> 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(); 
    twoEnumerator.Dispose(); 
} 

Editar: Este último debe trabajar con C# 3.5.

+0

Creo que te refieres a .NET 3.5. No hay tal cosa como C# 3.5. Deberías usar el uso de instrucciones en lugar de llamar manualmente a Dispose. Tenga en cuenta que no se requiere nada en las respuestas existentes * C# 4 * - solo requiere * .NET 4 *, al igual que su respuesta, porque usa Tuple. –

0

he aquí una solución que funcionará en C# 3 y .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 }; 

iterar sobre la consulta produciría pares que contienen 1,2 & 9,4 y 17,8 & 26.2. Los dos pares del medio se descartarían porque uno contiene NaN y el otro contiene infinito.

foreach (var pair in query) 
{ 
    Console.WriteLine("{0}\t{1}", pair.X, pair.Y); 
} 
2

Bien, entonces no puede usar .NET 4.0 y por lo tanto no puede usar la extensión Zip.

O puede usted?

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); 
    } 
} 

Vea usted mismo :)

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); 
} 

Salida:

X: 0, Y: 0.5 
X: 1, Y: 1.5 
X: 4, Y: 4.5 
X: 5, Y: 5.5 
+0

Gracias, gran ejemplo de creación de extensiones. Me puede ayudar algún día;) ¡Gracias por tu ayuda! – Gacek

Cuestiones relacionadas