我在使用带有匿名函数的Select或在运行时计算的其他值时注意到的是,每次访问输出IEnumerable对象时,投影都会重新计算该值。例如:
#Importamos librerias
from math import log,exp,sqrt
from scipy import stats
#Definimos nuestra funcion acumulativa
N = stats.norm.cdf
#Definimos la formula de Black Scholes para una opción Call
def BS(S0,K,T,r,sigma):
S0 = float(S0)
d1 = (log(S0/K)+(r + 0.5 * sigma**2)*T)/(sigma*sqrt(T))
d2 = (log(S0/K)+(r - 0.5*sigma**2)*T)/(sigma*sqrt(T))
value = (S0*N(d1)-K*exp(-r*T)*N(d2))
return value
#Definimos Vega que es la derivada con respecto de sigma
def Vega(S0,K,T,r,sigma):
S0 = float(S0)
d1 = (log(S0/K)+(r + 0.5 * sigma**2)*T)/(sigma*sqrt(T))
vega = S0 * N(d1)*sqrt(T)
return vega
#Definimos la volatilidad implicita usando BS y Vega, usamos el metodo de
#Newton para resolver
def ImpliedVol(S0, K, T, r, C0, sigma_est, it=100):
for i in range(it):
sigma_est -= ((BS(S0,K,T,r, sigma_est)-C0)/Vega(S0,K,T,r,sigma_est))
return sigma_est
#Calculamos de Acuerdo a los parametros
S0 = 173
K = 130
T = 0.02
r = 0.029
C0 = 42
Sigma_init = 0.5
print(ImpliedVol(S0,K,T,r,C0,Sigma_init))
我注意到每次我通过列表listOfB解析并使用Id属性时,ID会被另一个public class A
{
public string Name { get; set; }
public string Addr { get; set; }
}
public class B
{
public A Whatever {get;set;}
public int Id {get;set;}
}
Random rand = new Random();
IEnumerable<B> listOfBs = someListOfA.Select( x => new B()
{
Id = rand.Next(),
Whatever = x
});
重新评估。
rand.Next()
在C#投影的文档中,我还没有看到会导致这种情况的原因。它几乎就像Select生成一个匿名函数,每次访问它时都会重新评估。所以,有两个问题:
如果我的错误示例代码传达了我的观点,请告诉我。
答案 0 :(得分:4)
这是预期的,因为大多数LINQ方法都是懒惰的 - 这意味着在需要结果之前,他们不会枚举源代码。在您特定的情况下,listOfBs
实际上不是B
个对象的物化集合。相反,它是如何将someListOfA
转换为B
对象集合的定义。 Select
返回一个实现IEnumerable<T>
的对象,并存储对源集合和投影委托的引用。当需要结果时进行投影,例如,当你在foreach
中迭代集合时。如果多次迭代,将多次执行投影。这正是你所看到的。
致电ToList
或ToArray
以立即实现结果:
IEnumerable<B> listOfBs = someListOfA.Select( x => new B()
{
Id = rand.Next(),
Whatever = x
}).ToList();