Linq选择具有计算值的投影

时间:2018-02-22 17:56:21

标签: c# linq projection

我在使用带有匿名函数的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生成一个匿名函数,每次访问它时都会重新评估。所以,有两个问题:

  1. 我看到的这种行为是什么。
  2. 如何避免这种情况,但仍然可以将一种类型的列表转换为另一种类型的另一种列表。
  3. 如果我的错误示​​例代码传达了我的观点,请告诉我。

1 个答案:

答案 0 :(得分:4)

这是预期的,因为大多数LINQ方法都是懒惰的 - 这意味着在需要结果之前,他们不会枚举源代码。在您特定的情况下,listOfBs实际上不是B个对象的物化集合。相反,它是如何someListOfA转换为B对象集合的定义。 Select返回一个实现IEnumerable<T>的对象,并存储对源集合和投影委托的引用。当需要结果时进行投影,例如,当你在foreach中迭代集合时。如果多次迭代,将多次执行投影。这正是你所看到的。

致电ToListToArray以立即实现结果:

IEnumerable<B> listOfBs = someListOfA.Select( x => new B()
{
    Id = rand.Next(),
    Whatever = x
}).ToList();