在浮点数列表中查找 NaN 并将上一个和下一个元素设置为 NaN

Posted

技术标签:

【中文标题】在浮点数列表中查找 NaN 并将上一个和下一个元素设置为 NaN【英文标题】:Find NaN in list of floats and set previous and next element to NaN 【发布时间】:2015-09-27 20:41:28 【问题描述】:

我有一个List<float> 和一些NaN。我想通过1 扩展NaN 区域。换句话说,如果我找到一个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 

【问题讨论】:

你不需要ll[i] = float.NaN;,因为它已经在那里了。 l.Select(item =&gt; item).ToList(); 可以是 l.ToList()new List&lt;float&gt;(l) 确实如此。这些改进稍微简化了代码。 需要复制列表吗?我意识到当前的实现要求它避免将数组填充到最后,但如果你能避免这种情况,你不能直接修改集合吗? 我可能首先列出 NaN 的索引,然后根据该列表找到应该更改的位置。此列表可能会比复制的列表短。 【参考方案1】:

这是一个只使用一个选择的实现:

l.Select((item, index) => index > 0 && float.IsNaN(l[index - 1]) || index < l.Count - 1 && float.IsNaN(l[index + 1]) ? float.NaN : item)

【讨论】:

如果列表中的最后一项是数字,这将不起作用 - 它不会将1 2 3 转换为NaN 2 NaN,而是将NaN 2 3。然而人们盲目地支持这个不正确的答案。 @Sinatr 不幸的是,您没有在问题中提及此要求。要将列表中的第一项和最后一项替换为 NaN,您可以使用我的查询的修改版本:l.Select((item, index) =&gt; index == 0 || index == l.Count - 1 || float.IsNaN(l[index - 1]) || float.IsNaN(l[index + 1]) ? float.NaN : item) 我不是op。 op 隐含地提到了这一点(检查他的输入字符串和想要的结果)。您之前评论中的代码也不起作用。随意fiddle。如果您设法使其工作,您可以编辑您的答案以添加改进的代码。 @Sinatr,对不起,他甚至没有含蓄地提到这个要求。输入字符串中的最后一项是 9(在原始问题中,而不是在您的答案中)。并且应该用 NaN 替换它,因为输入列表中的前一项是 NaN,而不是因为它是列表中的最后一项。你的小提琴有错误。您的代码会打印两次源列表,而不是打印查询结果。请结帐this 对不起,我昨天晚上在测试你的代码时犯了一个错误。该新版本在末尾正确处理多个数字的序列。 OP 确实提到了不是NaN 的序列,here 证明了您的答案中的第一个版本的代码不能在最后仅使用 2 个数字。第二种方法(已注释)工作正常,考虑将其放入答案中,我将删除我所有的 complains cmets ;)【参考方案2】:

您可以使用 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 );

【讨论】:

我喜欢这个是因为它的可读性和简洁性。甚至不需要列表副本。 如果将 SelectMany 部分更改为:.SelectMany(num => Enumerable.Range(num - margin, (margin * 2) + 1)),则可以进行变量maring【参考方案3】:

您可以使用其他方法扩展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

【讨论】:

【参考方案4】:

这个怎么样:

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 可以更简单。

【讨论】:

以上是关于在浮点数列表中查找 NaN 并将上一个和下一个元素设置为 NaN的主要内容,如果未能解决你的问题,请参考以下文章

Python:在浮动列表中查找最小项目的索引[重复]

如何使用 PANDAS 获取具有 NAN 值的列名并将这些列名存储在列表中? [复制]

如何将字符串列表转换为c#中的浮点列表,统一?

将上一个和下一个按钮添加到 li item php 或 jquery

RMS 的快速计算在 Java 中给出了 NaN - 浮点错误?

从元组列表中获取具有“NaN”的元组索引