C# 在字典中查找差异最小的键
说吧,我有这个收藏,它是通用字典C# 在字典中查找差异最小的键,c#,linq,dictionary,C#,Linq,Dictionary,说吧,我有这个收藏,它是通用字典 var items = new Dictionary<int, SomeData> { { 1 , new SomeData() }, { 5 , new SomeData() }, { 23 , new SomeData() }, { 22 , new SomeData() }, { 2 , new SomeData() }, { 7 , new SomeData() }, { 59
var items = new Dictionary<int, SomeData>
{
{ 1 , new SomeData() },
{ 5 , new SomeData() },
{ 23 , new SomeData() },
{ 22 , new SomeData() },
{ 2 , new SomeData() },
{ 7 , new SomeData() },
{ 59 , new SomeData() }
}
var allPair = items.SelectMany((l) => items.Select((r) => new {l,r}).Where((pair) => l.Key != r.Key));
问题:如何在通用字典中找到键之间的最小差异?是否有一种LINQ解决方案
目的:如果有多个匹配项,那么我只需要一个匹配项-最小的,这是用来填补项目之间缺少的关键点(间隙)不确定Linq是否最合适,但是(大致)这方面应该可以做到:
var smallestDiff = (from key1 in items.Keys
from key2 in items.Keys
where key1 != key2
group new { key1, key2 } by Math.Abs (key1 - key2) into grp
orderby grp.Key
from keyPair in grp
orderby keyPair.key1
select keyPair).FirstOrDefault ();
我不知道如何在LINQ中一行完成,但这是解决这个问题的多行解决方案
var items = new Dictionary<int, string>();
items.Add(1, "SomeData");
items.Add(5, "SomeData");
items.Add(23, "SomeData");
items.Add(22, "SomeData");
items.Add(2, "SomeData");
items.Add(7, "SomeData");
items.Add(59, "SomeData");
var sortedArray = items.Keys.OrderBy(x => x).ToArray();
int minDistance = int.MaxValue;
for (int i = 1; i < sortedArray.Length; i++)
{
var distance = Math.Abs(sortedArray[i] - sortedArray[i - 1]);
if (distance < minDistance)
minDistance = distance;
}
Console.WriteLine(minDistance);
var items=newdictionary();
增加(1,“某些数据”);
增加(5,“某些数据”);
增加(23,“某些数据”);
增加(22,“某些数据”);
增加(2,“某些数据”);
增加(7,“某些数据”);
增加(59,“某些数据”);
var sortedArray=items.Keys.OrderBy(x=>x.ToArray();
int minDistance=int.MaxValue;
for(int i=1;i
我不会给你LinQ查询,因为已经有答案了。
我知道这不是您所要求的,但如果性能和易读性是您关心的问题,我想向您展示如何以非常快速和易于理解/维护的方式解决它
int[] keys;
int i, d, min;
keys = items.Keys.ToArray();
Array.Sort(keys); // leverage fastest possible implementation of sort
min = int.MaxValue;
for (i = 0; i < keys.Length - 1; i++)
{
d = keys[i + 1] - key[i]; // d is always non-negative after sort
if (d < min)
{
if (d == 2)
{
return 2; // minimum 1-gap already reached
} else if (d > 2) // ignore non-gap
{
min = d;
}
}
}
return min; // min contains the minimum difference between keys
这意味着什么
假设具有1-gap的概率很高,如果您已达到该最小gap,则每次更改min
时检查可能会更快。这可能发生在您通过for循环的概率为1%或10%时。因此,对于非常大的集合(例如,超过100万或10亿),一旦您知道预期的概率,这种概率方法可能会给您带来巨大的性能收益
相反,对于较小的集或1-gap的概率较低时,这些额外的CPU周期会被浪费,如果不进行检查,情况会更好
与非常大的数据库(考虑概率索引)一样,概率推理也变得相关
问题是,你必须事先估计概率效应是否以及何时起作用,这是一个相当复杂的话题
编辑2:1-gap的索引差实际上为2
。此外,1
的索引差是一个非间隙(在两者之间没有插入索引的间隙)
因此,前面的解决方案完全是错误的,因为一旦两个索引是连续的(比如34,35),最小值将是1
,这根本不是一个间隙
由于这个间隙问题,内部
if()
是必要的,此时概率方法的开销为零。使用正确的代码和概率的方法会更好 我认为LINQ是最简单的
首先,从你的字典中找出差异对
var items = new Dictionary<int, SomeData>
{
{ 1 , new SomeData() },
{ 5 , new SomeData() },
{ 23 , new SomeData() },
{ 22 , new SomeData() },
{ 2 , new SomeData() },
{ 7 , new SomeData() },
{ 59 , new SomeData() }
}
var allPair = items.SelectMany((l) => items.Select((r) => new {l,r}).Where((pair) => l.Key != r.Key));
然后求微分的最小值
allPair.OrderBy((pair) => Math.Abs(pair.l.Key - pair.r.Key)).FirstOrDefault();
但您可能有多个具有相同差值的对,因此您可能需要在使用OrderBy之前使用GroupBy,然后自己处理多个对,答案中未列出一行解决方案:
items.Keys.OrderBy(x => x).Select(x => new { CurVal = x, MinDist = int.MaxValue }).Aggregate((ag, x) => new { CurVal = x.CurVal, MinDist = Math.Min(ag.MinDist, x.CurVal - ag.CurVal) }).MinDist
这闻起来像是一种味道。为什么需要计算关键点之间的最小值?当有超过一分钟的比赛时,你会期望发生什么?@YuvalItzchakov:更新的有目的的问题Linq并不总是所有问题的答案。试着编写一个函数来实现这一点-这可能比你想象的要简单。顺便说一句,你可以使用实际的字典初始值设定项,而不是不会编译的
x=>y
。@Matíasfidemrazizer:提到的集合是一个伪代码,我说这是一个字典只是为了简单,我知道如何在.NETThanks中实例化泛型集合,尽管这将是一个相当大的集合,因此我不想重复它,不幸的是,这个示例包含了太多的泛型集合,这正是我认为Linq不合适的原因;)@阿姆:嗯,对于那些熟悉LINQ的人来说,它看起来确实足够简单和简洁,尽管在这种特殊情况下,就性能而言,最好还是使用commonloop@Andy顺便说一句,性能考虑是相对于您的具体用例中的实际性能影响…您应该添加低指数(i-1)或者可以使用一个数组来保留所选密钥对的位置(或直接值),以防出现多个匹配被否决的情况,但Oleg的答案是第一个,因此,所有的信用都归他所有。没关系,你可以自由决定谁投赞成票或反对票,或者应用什么道德推理。尽管如此,请看我所做的编辑,它可能与您相关:)我喜欢您关于最小间隙的想法,一般来说,它肯定会提高性能,但在我的例子中,日期作为键的格式为“纪元后秒”,unix时间戳,它们之间的最小步长可能会有所不同,例如,如果字典中的项为小时,则最近键之间的最小步长应等于3600秒(1小时),如果项为天,则最小步长为86400秒(1天),依此类推。。。