使用 LINQ 从 C# 泛型字典中查询值

Query values from a C# Generic Dictionary using LINQ

这是我的代码:

Dictionary<double, long> dictionary = new Dictionary<double, long>();
dictionary.Add(99, 500);
dictionary.Add(98, 500);
dictionary.Add(101, 8000);
dictionary.Add(103, 6000);
dictionary.Add(104, 5);
dictionary.Add(105, 2000);

double price = 100;

我想要的查询是: 最接近价格且具有最低值的键。 所以在上面的例子中它应该是 return 99。 我如何在 LINQ 中对此进行编码? 我看过很多 linq 示例,但我无法根据自己的需要调整其中任何一个 b/c 我的查询有 2 个条件。

感谢您的帮助。

编辑: 根据@nintendojunkie 和@DmitryMartovoi 的评论,我不得不重新考虑我的方法。 如果我优先考虑最接近价格的键,那么结果值可能不是最低的,如果我首先优先考虑值,那么键可能离价格太远,所以查询必须优先考虑键和值,并给我最低的值用最接近价格的钥匙。 key 和 value 同样重要。 有人可以帮忙吗? 谢谢

你可以这样做:

var result = dictionary.Select(c => new { c.Key, Diff = Math.Abs(price - c.Key) + Math.Abs(price - c.Value), c.Value }).OrderBy(c => c.Diff).FirstOrDefault();
var price = 100.0;

var nearestKey = (from pair in dictionary
                 let diff = Math.Abs(pair.Key - price)
                 select new {Key = pair.Key, Diff = diff}
                 order by diff desc).First().Key;
var minValue = dictionary[nearestKey];

也许你想要一个神奇的 linq 查询,但我建议试试下面的查询。

public static class MyExtensions
{
    public static double? GetNearestValue (this IDictionary<double, long> dictionary, double value)
    {
        if (dictionary == null || dictionary.Count == 0)
            return null;

        double? nearestDiffValue = null;
        double? nearestValue = null;

        foreach (var item in dictionary) {
            double currentDiff = Math.Abs (item.Key - value);
            if (nearestDiffValue == null || currentDiff < nearestDiffValue.Value) {
                nearestDiffValue = currentDiff;
                nearestValue = item.Value;
            }
        }

        return nearestValue;
    }
}

然后这样调用

Console.WriteLine (dictionary.GetNearestValue (100d));
var min = dictionary
            .OrderBy(pair => pair.Value)
            .Select(pair =>
                new
                {
                    k = pair.Key,
                    d = Math.Abs(pair.Key - price)
                })
            .OrderBy(t => t.d)
            .Select(t => t.k)
            .FirstOrDefault();

别忘了——你用的是字典。字典只有唯一的键。我想你认为这个结构是 List<KeyValuePair<double, long>>。如果是这样 - 请看这个例子:

var minimumKeyDifference = dictionary.Min(y => Math.Abs(y.Key - price));
var minimumItems = dictionary.Where(x => Math.Abs(x.Key - price).Equals(minimumKeyDifference));
var desiredKey = dictionary.First(x => x.Value.Equals(minimumItems.Where(y =>  y.Key.Equals(x.Key)).Min(y => y.Value))).Key;

如果您将字典键的数据类型更改为 decimal 而不是 double,则以下内容有效。

decimal price = 100;
decimal smallestDiff = dictionary.Keys.Min(n => Math.Abs(n - price));
var nearest = dictionary.Where(n => Math.Abs(n.Key - price) == smallestDiff)
                        .OrderBy(n => n.Value).First();

如果您使用 double,这可能会由于四舍五入问题而失败,但是 decimal 是与金钱有关的任何事情的首选,以避免这些问题。

你说你需要找到最接近的价格最低的值,但你没有定义两者之间的优先级分配规则。在下面,我赋予它们相同的优先级:1 的价格距离相当于 1 的值。

var closest = 
    dictionary.OrderBy(kvp => Math.Abs(kvp.Key - price) + kvp.Value).First();

为了性能,OrderBy(…).First() 应替换为 MinBy(…) 运算符(如果可用)。

编辑:如果该值仅用作决胜局,则使用此(也由 发布):

var closest = 
    dictionary.OrderBy(kvp => Math.Abs(kvp.Key - price))
              .ThenBy(kvp => kvp.Value)
              .First();