我有两个相同大小的双精度数组,包含一些情节的X和Y值。
我需要针对INF / NaN值创建某种保护。我需要找到所有的值对(X,Y),其中X和Y都不是INF也不是NaN
如果我有一个数组,我可以使用lambdas:
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。
答案 0 :(得分:6)
Mark的原始答案稍作修正:
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();
答案 1 :(得分:2)
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 :(得分:2)
好的,所以你不能使用.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
答案 3 :(得分:0)
您可以尝试这样做:
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<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(); }
编辑后者应与C#3.5配合使用。
答案 4 :(得分:0)
这是一个适用于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&amp;的对。 9.4和17.8&amp; 26.2。中间两对将被丢弃,因为一个包含NaN而另一个包含无穷大。
foreach (var pair in query)
{
Console.WriteLine("{0}\t{1}", pair.X, pair.Y);
}