【问题标题】:Check if any item in a list matches any item in another list检查列表中的任何项目是否与另一个列表中的任何项目匹配
【发布时间】:2010-03-24 13:46:03
【问题描述】:

同事让我写一个单行来代替下面的方法:

public static bool IsResourceAvailableToUser(IEnumerable<string> resourceRoles, IEnumerable<string> userRoles)
{
    foreach (var userRole in userRoles)
        foreach (var resourceRole in resourceRoles)
            if (resourceRole == userRole)
                return true;
    return false;
}

Resharper 和我想出了这个:

public static bool IsResourceAvailableToUser(IEnumerable<string> resourceRoles, IEnumerable<string> userRoles)
{
    return userRoles.Where(resourceRoles.Contains).Count() > 0;
}

有没有更好的办法?

【问题讨论】:

    标签: c# algorithm .net-3.5


    【解决方案1】:

    鉴于 LINQ,是的:

    return userRoles.Intersect(resourceRoles).Any();
    

    请注意,除了使用 Intersect 将其转换为 O(m) + O(n) 而不是 O(m * n) 之外,使用 Any 比使用 Count() &gt; 0 更有效 - 你知道找到第一个匹配项后立即回答。

    【讨论】:

    • 这可能不是问的正确地方,但既然我们正在谈论它;我在哪里可以阅读和了解 LINQ 方法的性能注意事项。
    • 作为一个非 C# 的人出于兴趣(我抓住了“算法”标签),有什么保证这是线性的?当然,需要对集合进行排序:是吗?
    • @Steve:它使用哈希集,基本上 - 从 userRoles 构建哈希集应该摊销 O(m),并在哈希集中从 resourceRoles 查找每个项目应该是总共 O(n)。
    • 哦。非在线算法也存在 ;-) 谢谢。
    【解决方案2】:

    您可以编写一个通用的扩展方法来处理许多情况。函数本身的肉是一行。

    /// <summary>
    /// Compares both lists to see if any item in the enumerable 
    /// equals any item in the other enumerable. 
    /// </summary>
    public static bool AnyItem<T>(this IEnumerable<T> source, IEnumerable<T> other, IEqualityComparer<T> comparer = null)
    {
        return (comparer == null ? source.Intersect(other) : source.Intersect(other, comparer)).Any();
    }
    

    较旧,效率较低的答案

    public static bool AnyItem<T>(this IEnumerable<T> source, IEnumerable<T> other)
    {
        return source.Any(s => other.Any(o => EqualityComparer<T>.Default.Equals(s, o)));
    }
    

    认为这也比当前答案更有效(不是)。我必须检查获得 EqualityComparer 是否昂贵,但我愿意怀疑。


    您还可以扩展此函数以接受一个表达式,该表达式将评估要比较包含对象的枚举的哪些属性。

    public static bool AnyItem<T, TResult>(
            this IEnumerable<T> source, 
            IEnumerable<T> other, 
            Expression<Func<T, TResult>> compareProperty = null)
    {
        if (compareProperty == null)
        {
            return source.Any(s => other.Any(o => EqualityComparer<T>.Default.Equals(s, o)));
        }
    
        return source.Any(s => other.Any(o => 
                        EqualityComparer<TResult>.Default.Equals(
                        s.GetPropertyValue(compareProperty),
                        o.GetPropertyValue(compareProperty))));
    }
    
    public static TValue GetPropertyValue<TTarget, TValue>(
        this TTarget target, Expression<Func<TTarget, TValue>> memberLamda)
    {
        var memberSelectorExpression = memberLamda.Body as MemberExpression;
        var property = memberSelectorExpression?.Member as PropertyInfo;
        return (TValue)property?.GetValue(target);
    }
    

    【讨论】:

    • 不,至少在时间上,这比我的回答效率明显。它是 O(a*b) 而不是 O(a+b),其中 a 是 source 中的项目数,b 是 other 中的项目数。这是空间中的 O(1),而我的空间是 O(n)。
    • @JonSkeet 我不得不仔细检查你,在这种情况下,Intersect 有多好实际上是非常了不起的,在 Any 的一些最佳情况下它甚至接近。我肯定会修改答案,但 OP 可能应该将你的答案标记为已接受的答案
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-24
    • 2012-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多