在浮点数列表中查找 NaN 并将上一个和下一个元素设置为 NaN
Find NaN in list of floats and set previous and next element to NaN
我有一个 List<float>
,到处都是 NaN
。我想将 NaN
区域扩展 1
。换句话说,如果我找到一个 NaN
元素,我希望上一个和下一个元素也变成 NaN
。
我编写了一些有效的代码,但在我看来它可以更简单。有什么建议吗?
List<float> l = new List<float>() { float.NaN, 1, 2, 3, float.NaN, float.NaN, float.NaN, 4, 5, 6, float.NaN, 7, 8, float.NaN, 9 };
Console.WriteLine(string.Join(" ", l));
List<float> ll = l.Select(item => item).ToList(); // clone list
for (int i = 0; i < l.Count; i++)
{
if (!float.IsNaN(l[i]))
continue;
if (i > 0)
ll[i - 1] = float.NaN;
ll[i] = float.NaN;
if (i < l.Count - 1)
ll[i + 1] = float.NaN;
}
Console.WriteLine(string.Join(" ", ll));
Console.ReadKey();
输出:
NaN 1 2 3 NaN NaN NaN 4 5 6 NaN 7 8 NaN 9
NaN NaN 2 NaN NaN NaN NaN NaN 5 NaN NaN NaN NaN NaN NaN
这里是一个只使用一个的实现select:
l.Select((item, index) => index > 0 && float.IsNaN(l[index - 1]) || index < l.Count - 1 && float.IsNaN(l[index + 1]) ? float.NaN : item)
您可以使用另一种方法展开NaN
。请注意扩展是 消耗 数字系列中的第一个和最后一个数字:
x --- NaN
x y --- NaN NaN
x y z --- NaN y NaN
x y z w --- NaN y z NaN
...
不理想,只是一个例子(这里是 fiddle 可以玩):
var list = new List<float>() { float.NaN, 1, 2, 3, float.NaN, float.NaN, float.NaN, 4, 5, 6, float.NaN, 7, 8, float.NaN, 9, float.NaN, 10, 11, 12, 13 };
Console.WriteLine(string.Join(" ", list.Select(o => o.ToString().PadLeft(3))));
int counter = 0;
for (int i = 0; i < list.Count; i++)
{
if(!float.IsNaN(list[i]))
{
// increment counter if number and replace first in serie with NaN
if(counter++ == 0)
list[i] = float.NaN;
}
else
// serie finished? replace last number in it with NaN
if(counter != 0)
{
list[i - 1] = float.NaN;
counter = 0; // reset count
}
}
// special test if last item in list is a number
// serie finished? replace last number in it with NaN
if(counter != 0)
list[list.Count - 1] = float.NaN;
Console.WriteLine(string.Join(" ", list.Select(o => o.ToString().PadLeft(3))));
输出(我在末尾添加了 4 个数字的系列):
NaN 1 2 3 NaN NaN NaN 4 5 6 NaN 7 8 NaN 9 NaN 10 11 12 13
NaN NaN 2 NaN NaN NaN NaN NaN 5 NaN NaN NaN NaN NaN NaN NaN NaN 11 12 NaN
您可以使用 Linq 获取需要更改的索引,然后强制更新列表的副本。
var theNewNanIndexes = Enumerable.Range( 0, l.Count )
.Where( num => float.IsNaN(l[num]))
.SelectMany( num => new[]{ num - 1, num + 1 } )
.Where( num => num >= 0 && num < l.Count) ;
ll = new List<float>(l);
theNewNanIndexes.ToList().ForEach( num => ll[num] = float.NaN );
这个怎么样:
private bool IsAdjacentNaN(List<float> list, int index)
{
var beforeNaN = index != 0 && float.IsNaN(list[index - 1]);
var afterNaN = (index + 1 != list.Count) && float.IsNaN(list[index + 1]);
return beforeNaN || afterNaN;
}
List<float> l = ...;
var results = l.Select((x,i) => IsAdjacentNaN(l,i) ? float.NaN : x);
在此示例中,IsAdjacentNaN 抽象了复杂性,因此您的 lambda 可以更简单。
我有一个 List<float>
,到处都是 NaN
。我想将 NaN
区域扩展 1
。换句话说,如果我找到一个 NaN
元素,我希望上一个和下一个元素也变成 NaN
。
我编写了一些有效的代码,但在我看来它可以更简单。有什么建议吗?
List<float> l = new List<float>() { float.NaN, 1, 2, 3, float.NaN, float.NaN, float.NaN, 4, 5, 6, float.NaN, 7, 8, float.NaN, 9 };
Console.WriteLine(string.Join(" ", l));
List<float> ll = l.Select(item => item).ToList(); // clone list
for (int i = 0; i < l.Count; i++)
{
if (!float.IsNaN(l[i]))
continue;
if (i > 0)
ll[i - 1] = float.NaN;
ll[i] = float.NaN;
if (i < l.Count - 1)
ll[i + 1] = float.NaN;
}
Console.WriteLine(string.Join(" ", ll));
Console.ReadKey();
输出:
NaN 1 2 3 NaN NaN NaN 4 5 6 NaN 7 8 NaN 9
NaN NaN 2 NaN NaN NaN NaN NaN 5 NaN NaN NaN NaN NaN NaN
这里是一个只使用一个的实现select:
l.Select((item, index) => index > 0 && float.IsNaN(l[index - 1]) || index < l.Count - 1 && float.IsNaN(l[index + 1]) ? float.NaN : item)
您可以使用另一种方法展开NaN
。请注意扩展是 消耗 数字系列中的第一个和最后一个数字:
x --- NaN
x y --- NaN NaN
x y z --- NaN y NaN
x y z w --- NaN y z NaN
...
不理想,只是一个例子(这里是 fiddle 可以玩):
var list = new List<float>() { float.NaN, 1, 2, 3, float.NaN, float.NaN, float.NaN, 4, 5, 6, float.NaN, 7, 8, float.NaN, 9, float.NaN, 10, 11, 12, 13 };
Console.WriteLine(string.Join(" ", list.Select(o => o.ToString().PadLeft(3))));
int counter = 0;
for (int i = 0; i < list.Count; i++)
{
if(!float.IsNaN(list[i]))
{
// increment counter if number and replace first in serie with NaN
if(counter++ == 0)
list[i] = float.NaN;
}
else
// serie finished? replace last number in it with NaN
if(counter != 0)
{
list[i - 1] = float.NaN;
counter = 0; // reset count
}
}
// special test if last item in list is a number
// serie finished? replace last number in it with NaN
if(counter != 0)
list[list.Count - 1] = float.NaN;
Console.WriteLine(string.Join(" ", list.Select(o => o.ToString().PadLeft(3))));
输出(我在末尾添加了 4 个数字的系列):
NaN 1 2 3 NaN NaN NaN 4 5 6 NaN 7 8 NaN 9 NaN 10 11 12 13
NaN NaN 2 NaN NaN NaN NaN NaN 5 NaN NaN NaN NaN NaN NaN NaN NaN 11 12 NaN
您可以使用 Linq 获取需要更改的索引,然后强制更新列表的副本。
var theNewNanIndexes = Enumerable.Range( 0, l.Count )
.Where( num => float.IsNaN(l[num]))
.SelectMany( num => new[]{ num - 1, num + 1 } )
.Where( num => num >= 0 && num < l.Count) ;
ll = new List<float>(l);
theNewNanIndexes.ToList().ForEach( num => ll[num] = float.NaN );
这个怎么样:
private bool IsAdjacentNaN(List<float> list, int index)
{
var beforeNaN = index != 0 && float.IsNaN(list[index - 1]);
var afterNaN = (index + 1 != list.Count) && float.IsNaN(list[index + 1]);
return beforeNaN || afterNaN;
}
List<float> l = ...;
var results = l.Select((x,i) => IsAdjacentNaN(l,i) ? float.NaN : x);
在此示例中,IsAdjacentNaN 抽象了复杂性,因此您的 lambda 可以更简单。