【问题标题】:Linq to objects: if number is in dictionary, return number, else return 0Linq to objects:如果数字在字典中,则返回数字,否则返回 0
【发布时间】:2011-07-02 15:19:01
【问题描述】:

我有一个Dictionary<int int>。当我检查字典的键是否有数字并且它在其中时,我希望它返回数字,否则我希望 linq 查询返回 0。

类似下面的东西,除了工作

var t = (from result in results
         where result.Key == 3
         select result.Key != null ? result.Value : 0).First();

因为问题是当列表中没有数字时,序列中不包含任何元素,所以不能用null或者count来检查。

【问题讨论】:

  • 我无法从您的示例中看出,但如果您始终存储相同的键和值(key == value),那么您可以使用HashMap<int>
  • 它是什么,我正在开发一个 F1 应用程序,这部分应该存储一个位置以及该位置的点。不过,积分可能会发生变化(尽管这更多的是几年的时间)。
  • 抱歉,无法编辑我的评论。我的意思是:它是什么,我正在开发一个 F1 应用程序,这本字典应该存储一个 driverId 以及该驱动程序的分数。 driverId 是键,值是司机得分。我只会存储前 10 个车手(FIA 规则)。

标签: c# c#-4.0 linq-to-objects


【解决方案1】:

只需使用TryGetValue

int i;
results.TryGetValue(3, out i);

如果找到它,则将i 设置为该值。如果不是,i 是默认值,int 为零。

如果你想要除默认值之外的另一个值,你可以这样做:

int i;
if (!results.TryGetValue(3, out i))
{
    i = 5; // or whatever other value you want;
}

如果你和我一样讨厌out 参数风格,你可以创建一个扩展方法

public static class IDictionaryExtensions
{
    public static TValue GetValueOrDefault<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
    {
        T i;
        dictionary.TryGetValue(key, out i);
        return i;
    }
}

然后你可以调用:

int i = dictionary.GetValueOrDefault(3);

如果你想变得更漂亮,你可以创建另一个超载的扩展:

    public static TValue GetValueOrDefault<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, TValue defaultValue)
    {
        T i;
        return dictionary.TryGetValue(key, out i) ? i : defaultValue;
    }

可以调用的

int i = dictionary.GetValueOrDefault(3, 5);

【讨论】:

  • 这很整洁。但是当你想要一个不同于默认值的值时,你会怎么做?
  • @Garth Marenghi,我添加了许多其他示例和帮助程序。好问题。
  • 谢谢,这对我帮助很大!
【解决方案2】:

为什么不直接

var t = results.ContainsKey(3) ? results[3] : 0;

完全绕过对 LINQ 的需求?

【讨论】:

  • 当您只能进行一次查找时,为什么还要进行两次查找?这正是 TryGetValue 的用途。
  • @Samuel:嗯,是的,TryGetValue 可以在这里工作,但是使用起来有点笨拙(因为out 参数,它必须是一个预先声明的变量,并且不能是一个属性)。在一般情况下,如果所需的默认值不是default(T),则使用起来会更加烦人。另外,我怀疑一次额外的查找会显着影响性能。
  • 我用一种扩展方法更新了我的答案,解决了您对out 参数的可理解的厌恶。
  • @Samuel:+1,我喜欢你的扩展方法
【解决方案3】:
return results.ContainsKey(key) ? results[key] : 0;

【讨论】:

  • 当您只能进行一次查找时,为什么还要进行两次查找?这正是 TryGetValue 的用途。
  • Samuel:是的,我会继续给你一个打击。
【解决方案4】:

听起来results 是你的字典。

Dictionary<int int> results = new Dictionary<int,int>{{1,1},{3,3}};
int value;
results.TryGetValue (4, out value);
return value;

value0,因为TryGetValue 将其设置为default(int),当然是0

如果您想键入更多内容、混淆阅读您的代码的人并减慢速度,您可以使用 linq。这不会使用哈希码,因此它是一个缓慢的查找 Big O(n)。

var t = (from result in results
      where result.Key == 3
      select result.Key != null ? result.Value : 0).FirstOrDefault();

【讨论】:

  • Results 确实是我的字典。该字典应存储 driverId 以及该驱动程序的点数。 driverId 是 key,value 是司机得分。我将只存储前 10 个驱动程序(FIA 规则),因此对于所有其他驱动程序,我的方法应该返回一个零
【解决方案5】:

试试var t = (from result in results where result.Key == 3 select result.Value).FirstOrDefault();

现在,要么你在 where 子句中有一个匹配项,所以 select 将投影正确的值,要么你有一个空序列。 FirstOrDefault() 然后返回值(如果存在)或 0(整数的默认值。)

【讨论】:

  • 这在语义上与 OP 要求的不同。如果字典包含key,则代码应返回key 的值,否则为0。
  • @Ed S. 这行得通。这是超级低效的,但它会工作。它将遍历结果,对 key 为 3 的结果进行微调,并返回该结果的值。如果没有找到,它将返回默认值,即 0。这是正确的。虽然很愚蠢,因为我们将字典视为不必要的列表,但这是 OP 要求的。
  • 它是什么,我正在开发一个 F1 应用程序,这本字典应该存储一个 driverId 以及该驱动程序的积分。 driverId 是键,值是车手在特定比赛中得分。不过,您对 Silly 是什么意思,因为我们将字典视为不必要的列表?
【解决方案6】:

选择出来的值然后:

ToArray().FirstOrDefault()

【讨论】:

    猜你喜欢
    • 2015-01-18
    • 2011-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-26
    • 1970-01-01
    • 2013-12-11
    相关资源
    最近更新 更多