C# 如何用Linq表示Hellinger距离
我想用Linq表示下面的公式C# 如何用Linq表示Hellinger距离,c#,linq,C#,Linq,我想用Linq表示下面的公式 double result = (from i in Enumerable.Range(1, 100) let recStr = recording.FirstOrDefault(a => a.Strength == i) let readStr = reading.FirstOrDefault(a => a.Strength == i) let
double result = (from i in Enumerable.Range(1, 100)
let recStr = recording.FirstOrDefault(a => a.Strength == i)
let readStr = reading.FirstOrDefault(a => a.Strength == i)
let recVal = recStr == null ? 0 : recStr.Probability
let readVal = readStr == null ? 0 : readStr.Probability
select Math.Pow(Math.Sqrt(recVal) - Math.Sqrt(readVal), 2)).Sum();
return Math.Sqrt(result / 2);
double result = (from i in Enumerable.Range(1, 100)
let recStr = recording.FirstOrDefault(a => a.Strength == i)
let readStr = reading.FirstOrDefault(a => a.Strength == i)
let recVal = recStr == null ? 0 : recStr.Probability
let readVal = readStr == null ? 0 : readStr.Probability
select Math.Pow(Math.Sqrt(recVal) - Math.Sqrt(readVal), 2)).Sum();
return Math.Sqrt(result / 2);
我有以下功能
private double Calc(IEnumerable<Frequency> recording, IEnumerable<Frequency> reading)
{
}
double result = (from i in Enumerable.Range(1, 100)
let recStr = recording.FirstOrDefault(a => a.Strength == i)
let readStr = reading.FirstOrDefault(a => a.Strength == i)
let recVal = recStr == null ? 0 : recStr.Probability
let readVal = readStr == null ? 0 : readStr.Probability
select Math.Pow(Math.Sqrt(recVal) - Math.Sqrt(readVal), 2)).Sum();
return Math.Sqrt(result / 2);
对该函数的调用示例如下
public void Caller(){
IEnumerable<Frequency> recording = new List<Frequency>
{
new Frequency {Strength = 32, Probability = 0.2}, //p32 = 0.2
new Frequency {Strength = 33, Probability = 0.2}, //p33 = 0.2
new Frequency {Strength = 34, Probability = 0.2}, //p34 = 0.2
new Frequency {Strength = 35, Probability = 0.2}, //...
new Frequency {Strength = 41, Probability = 0.2} //...
};
IEnumerable<Frequency> reading = new List<Frequency>
{
new Frequency {Strength = 34, Probability = 0.2}, //q34 = 0.2
new Frequency {Strength = 35, Probability = 0.2}, //q35 = 0.2
new Frequency {Strength = 36, Probability = 0.2},
new Frequency {Strength = 37, Probability = 0.2},
new Frequency {Strength = 80, Probability = 0.2},
};
Calc(reading, recordig);
}
double result = (from i in Enumerable.Range(1, 100)
let recStr = recording.FirstOrDefault(a => a.Strength == i)
let readStr = reading.FirstOrDefault(a => a.Strength == i)
let recVal = recStr == null ? 0 : recStr.Probability
let readVal = readStr == null ? 0 : readStr.Probability
select Math.Pow(Math.Sqrt(recVal) - Math.Sqrt(readVal), 2)).Sum();
return Math.Sqrt(result / 2);
既不高效也不优雅。我觉得解决方案可以改进,但我想不出更好的方法。Resharper将您的功能转化为:
double result = (from i in Enumerable.Range(1, 100)
let recStr = recording.FirstOrDefault(a => a.Strength == i)
let readStr = reading.FirstOrDefault(a => a.Strength == i)
let recVal = recStr == null ? 0 : recStr.Probability
let readVal = readStr == null ? 0 : readStr.Probability
select Math.Pow(Math.Sqrt(recVal) - Math.Sqrt(readVal), 2)).Sum();
return Math.Sqrt(result / 2);
正如Patashu所说,您可以使用字典来获得O(1)查找时间:
double result = (from i in Enumerable.Range(1, 100)
let recStr = recording.FirstOrDefault(a => a.Strength == i)
let readStr = reading.FirstOrDefault(a => a.Strength == i)
let recVal = recStr == null ? 0 : recStr.Probability
let readVal = readStr == null ? 0 : readStr.Probability
select Math.Pow(Math.Sqrt(recVal) - Math.Sqrt(readVal), 2)).Sum();
return Math.Sqrt(result / 2);
private double Calc(Dictionary<int, Frequency> recording, Dictionary<int, Frequency> reading)
{
double result = (from i in Enumerable.Range(1, 100)
let recVal = recording.ContainsKey(i) ? 0 : recording[i].Probability
let readVal = reading.ContainsKey(i) ? 0 : reading[i].Probability
select Math.Pow(Math.Sqrt(recVal) - Math.Sqrt(readVal), 2)).Sum();
return Math.Sqrt(result / 2);
}
private double Calc(字典记录、字典阅读)
{
double result=(从可枚举范围(1100)中的i开始)
让recVal=recording.ContainsKey(i)?0:recording[i]。概率
设readVal=reading.ContainsKey(i)?0:reading[i]。概率
选择Math.Pow(Math.Sqrt(recVal)-Math.Sqrt(readVal),2)).Sum();
返回数学Sqrt(结果/2);
}
由于列表稀疏(我们没有所有读数的概率),这个问题变得复杂。因此,首先我们要解决这个问题:
double result = (from i in Enumerable.Range(1, 100)
let recStr = recording.FirstOrDefault(a => a.Strength == i)
let readStr = reading.FirstOrDefault(a => a.Strength == i)
let recVal = recStr == null ? 0 : recStr.Probability
let readVal = readStr == null ? 0 : readStr.Probability
select Math.Pow(Math.Sqrt(recVal) - Math.Sqrt(readVal), 2)).Sum();
return Math.Sqrt(result / 2);
public static IEnumerable<Frequency> FillHoles(this IEnumerable<Frequency> src, int start, int end) {
IEnumerable<int> range = Enumerable.Range(start, end-start+1);
var result = from num in range
join _freq in src on num equals _freq.Strength into g
from freq in g.DefaultIfEmpty(new Frequency { Strength = num, Probability = 0 })
select freq;
return result;
}
公共静态IEnumerable填充孔(此IEnumerable src,int start,int end){
IEnumerable range=可枚举范围(开始、结束开始+1);
var结果=范围内的从数值
将_freqin src on num equals _freq.Strength连接到g中
从g.DefaultIfEmpty中的freq(新频率{Strength=num,Probability=0})
选择频率;
返回结果;
}
这给我们留下了密集的频率读数阵列。现在我们只需要应用以下公式:
double result = (from i in Enumerable.Range(1, 100)
let recStr = recording.FirstOrDefault(a => a.Strength == i)
let readStr = reading.FirstOrDefault(a => a.Strength == i)
let recVal = recStr == null ? 0 : recStr.Probability
let readVal = readStr == null ? 0 : readStr.Probability
select Math.Pow(Math.Sqrt(recVal) - Math.Sqrt(readVal), 2)).Sum();
return Math.Sqrt(result / 2);
// Make the arrays dense
recording = recording.FillHoles(1, 100);
reading = reading.FillHoles(1, 100);
// This is the thing we will be summing
IEnumerable<double> series = from rec in recording
join read in reading on rec.Strength equals read.Strength
select Math.Pow(Math.Sqrt(rec.Probability)-Math.Sqrt(read.Probability), 2);
double result = 1 / Math.Sqrt(2) * Math.Sqrt(series.Sum());
result.Dump();
//使数组密集
记录=记录。填充孔(1100);
读数=读数。填充孔(1100);
//这就是我们要总结的东西
IEnumerable series=从记录中的记录
加入阅读练习,阅读强度等于阅读强度
选择Math.Pow(Math.Sqrt(rec.Probability)-Math.Sqrt(read.Probability),2);
double result=1/Math.Sqrt(2)*Math.Sqrt(series.Sum());
result.Dump();
不过,我不确定这是否比您现有的性能更好。我仍在学习LINQ表达式,一个很好的方法是使用Resharper VS扩展(您可以进行30天的试用)。这个工具提供了更简洁的语句替代方案,我可以从使用LINQ表达式中受益,也可以已经受益,但不要尽可能优雅地这样做。这只是一个想法和未来的努力!也许做一个从强度到频率的散列映射,然后你有O(1)个键查找,而不是O(n)个列表扫描来查找强度。优雅在旁观者的眼里,但你当前的代码看起来是可维护的,我认为这更重要。LINQ很棒,但在代码可读性和可维护性方面可能会被误用。使用循环没有什么错!
double result = (from i in Enumerable.Range(1, 100)
let recStr = recording.FirstOrDefault(a => a.Strength == i)
let readStr = reading.FirstOrDefault(a => a.Strength == i)
let recVal = recStr == null ? 0 : recStr.Probability
let readVal = readStr == null ? 0 : readStr.Probability
select Math.Pow(Math.Sqrt(recVal) - Math.Sqrt(readVal), 2)).Sum();
return Math.Sqrt(result / 2);