Проверьте, соответствует ли какой-либо элемент в списке любому элементу в другом списке - PullRequest
11 голосов
/ 24 марта 2010

Коулига попросила меня написать однострочник вместо следующего метода:

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

Решарпер и я придумали это:

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

Есть ли лучший способ?

Ответы [ 2 ]

23 голосов
/ 24 марта 2010

Учитывая LINQ, да:

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

Обратите внимание, что помимо использования Intersect для преобразования его в O (m) + O (n) вместо O (m * n), используя Any эффективнее, чем использование Count() > 0 - вы узнаете ответ, как только найдете первое совпадение.

2 голосов
/ 14 февраля 2017

Вы можете написать универсальный метод расширения, который будет обрабатывать многие случаи. Мясо самой функции - одна строка.

/// <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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...