说,我有这个集合,它是通用字典
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() }
}
在这种情况下,键之间的最小距离(差异)= 1,例如,在23到22之间或在1到2之间
23 - 22 = 1 or 2 - 1 = 1
问题:如何找到通用字典中键之间的最小差异?是否有一行LINQ解决方案?
目的:如果有多个匹配,那么我只需要一个 - 最小的,这需要填充项之间缺少的键(间隙)
答案 0 :(得分:3)
我不知道如何在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);
答案 1 :(得分:2)
不确定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 ();
答案 2 :(得分:2)
我不会给你一个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
因为只有一种,这种非LinQ解决方案的性能执行得非常快。 我不是说这是最好的方式,但只是你应该测量两种解决方案并比较性能。
编辑:根据您的目的,我添加了这篇文章:
if (d == 2)
{
return 2; // minimum 1-gap already reached
} else if (d > 2) // ignore non-gap
{
min = d;
}
现在这是什么意思?
假设有1个差距的概率很高,如果达到最小差距,则检查min
的每次更改可能会更快。基于概率,当你通过for循环为1%或10%时,可能会发生这种情况。因此,对于非常大的集合(例如,超过100万或10亿)并且一旦您知道预期的概率,这种概率方法可能会为您带来巨大的性能提升。
相反,对于小集或当1间隙的概率很低时,这些额外的CPU周期会被浪费掉,如果没有这个检查,你会更好。
与非常大的数据库(想想概率索引)一样,概率推理变得相关。
问题在于你必须事先估计概率效应是否以及何时开始,这是一个相当复杂的话题。
编辑2: 1-gap实际上的索引差异为2
。此外,1
的索引差异是非差距(在两者之间插入索引没有间隙)。
所以之前的解决方案是错误的,因为只要两个索引是连续的(比如34,35),最小值就是1
,这根本不是差距。
由于这个差距问题,内部if()
是必要的,此时概率方法的开销无效。使用正确的代码和概率方法会更好!
答案 3 :(得分:1)
我认为LINQ最简单
首先,从词典中制作差异对
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然后自己处理多对
答案 4 :(得分:1)
答案中未列出的单行解决方案:
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