我刚刚偶然发现了Python的这个有趣的行为,它涉及NaN
中的set
:
# Test 1
nan = float('nan')
things = [0, 1, 2, nan, 'a', 1, nan, 'a', 2, nan, nan]
unique = set(things)
print(unique) # {0, 1, 2, nan, 'a'}
# Test 2
things = [0, 1, 2, float('nan'), 'a', 1, float('nan'), 'a', 2, float('nan'), float('nan')]
unique = set(things)
print(unique) # {0, 1, 2, nan, nan, nan, nan, 'a'}
当然,同一个键nan
在最后一个set
中多次出现似乎很奇怪
我认为这是由于nan
与自身不相等(由IEEE 754定义),再加上在向set
添加对象时,对象是基于值相等之前的内存位置(id()
)进行比较的。然后,似乎每个float('nan')
都会产生一个新的对象,而不是返回一些全局“单例”float
(例如小整数)
问题:
things
。我如何计算实际唯一元素的数量?通常的len(set(things))
显然不起作用。事实上,我可以使用import numpy as np; len(np.unique(things))
,但我想知道这是否可以在不使用第三方库的情况下实现李>作为一个小附录,让我补充一点,类似的故事适用于dict
s:
d = {float('nan'): 0, float('nan'): 1}
print(d) # {nan: 0, nan: 1}
我的印象是NaN
在dict
中作为键是完全不可能的,但只要存储对用作键的确切对象的引用,它实际上就可以工作:
nan0 = float('nan')
nan1 = float('nan')
d = {nan0: 0, nan1: 1}
d[float('nan')] # KeyError
d[nan0] # 0
d[nan1] # 1
当然,这很有意思,但如果需要在现有的dict
中存储额外的值,并且不关心要使用哪些键,当然每个新键不必已经在dict
中,我可以看到这个技巧很有用。也就是说,可以使用float('nan')
作为工厂来生成新的dict
密钥的无止境供应,保证不会相互碰撞、现有或未来的密钥
float()
所需的行为是返回float(类)的实例。你说得对,“南”并不等于它本身。因此,float(1) == float(1)
而float('nan') != float('nan')
为了得到一个唯一的集合,我建议像在测试1中那样建立一个nan常量。如果这不适合你,你可以选择
import math; math.isnan(float('nan'))
。迭代列表(或集合)并删除元素。newlist = [ x for x in things if not math.isnan(x) ]
你可能会想:不,我删除所有的南。如果以前有一个呢
{0, 1, 2, nan}
相关问题 更多 >
编程相关推荐