开发者

Check if any item in a list matches any item in another list

开发者 https://www.devze.com 2022-12-24 04:27 出处:网络
A c开发者_StackOverflowoleague asked me to write a one-liner to replace the following method: public static bool IsResourceAvailableToUser(IEnumerable<string> resourceRoles, IEnumerable<stri

A c开发者_StackOverflowoleague asked me to write a one-liner to replace the following method:

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 and I came up with this:

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

Is there a better way?


Given LINQ, yes:

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

Note that aside from the use of Intersect to turn it into O(m) + O(n) instead O(m * n), using Any is more efficient than using Count() > 0 - you know the answer as soon as you've found the first match.


You could write a generic extension method that would handle many cases. The meat of the function itself is one line.

/// <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();
}

Older, Less efficient answer

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)));
}

I think this is also more efficient than the current answer (It's not). I would have to check if getting the EqualityComparer is expensive, but I'm willing to doubt it.


You could also extend this function to accept an Expression that would evaluate what properties to compare for enumerables that contain objects.

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);
}
0

精彩评论

暂无评论...
验证码 换一张
取 消