Проверьте, содержит ли list <t> какой-либо другой список


97

У меня есть список таких параметров:

public class parameter
{
    public string name {get; set;}
    public string paramtype {get; set;}
    public string source {get; set;}
}

IEnumerable<Parameter> parameters;

И массив строк, который я хочу проверить.

string[] myStrings = new string[] { "one", "two"};

Я хочу перебрать список параметров и проверить, равно ли исходное свойство какому-либо из массива myStrings. Я могу сделать это с помощью вложенных foreach, но я хотел бы узнать, как это сделать лучше, поскольку я играл с linq и мне нравились методы расширения в enumerable, например where и т.д., поэтому вложенные foreach просто кажутся неправильными. Есть ли более элегантный предпочтительный способ linq / lambda / delegete для этого.

Благодарность

Ответы:


208

Вы можете использовать вложенную Any()проверку, которая доступна на любом Enumerable:

bool hasMatch = myStrings.Any(x => parameters.Any(y => y.source == x));

Быстрее выступать на больших коллекций будет проект parametersдля , sourceа затем использовать , Intersectкоторый внутренне использует HashSet<T>так вместо O (N ^ 2) для первого подхода (эквивалент двух вложенных циклов) , вы можете сделать проверку в O (N):

bool hasMatch = parameters.Select(x => x.source)
                          .Intersect(myStrings)
                          .Any(); 

Также в качестве дополнительного комментария вы должны использовать заглавные буквы в именах классов и свойств, чтобы соответствовать рекомендациям по стилю C #.


спасибо, кажется, это то, что я ищу, я попробую. Нужно еще немного поэкспериментировать с функциональной стороной вещей. Что касается капитализации класса и свойств, я просто забыл, когда писал пример выше.
gdp

1
Почему O (n ^ 2)? Разве это не O (n * m), поскольку мы говорим о двух переменных, а не об одной? Поскольку m (параметры) являются константой, это то же самое, что и O (n). Я не понимаю, как здесь пересечение должно быть намного быстрее? Но согласен, Intersect может быть быстрее, но это не гарантируется.
Squazz

Вы правы, что это должно быть O (n * m) - m не является константой - это размер одного из списков, хотя в данном конкретном примере это может быть «2». Хотя даже постоянные значения на практике не пренебрежимо малы - для всех нетривиальных длин списков Intersectбудет быстрее - если списки тривиально короткие, это не имеет значения так или иначе (в этом случае производительность, вероятно, в любом случае не является вашей проблемой )
BrokenGlass

как определить индекс списка, в котором условие выполняется? У меня есть список предложений. У меня есть массив с определенными словами. Мне нужны индексы списка, если в предложении есть хотя бы одно слово из массива. @BrokenGlass
kirushan

1
С точки зрения производительности, не parameters.Any(x => myStrings.Contains(x.source));лучше, чем ваш первый пример?
Fluppe

3

Вот пример, чтобы узнать, есть ли совпадающие элементы в другом списке

List<int> nums1 = new List<int> { 2, 4, 6, 8, 10 };
List<int> nums2 = new List<int> { 1, 3, 6, 9, 12};

if (nums1.Any(x => nums2.Any(y => y == x)))
{
    Console.WriteLine("There are equal elements");
}
else
{
    Console.WriteLine("No Match Found!");
}

2
Обратите внимание, что если задействованные списки большие, это будет намного медленнее, чем Intersectподход, поскольку это O (N * M) в размерах списков. (Хотя это O (1) в памяти.)
Джон Скит,

1

Если оба списка слишком велики и когда мы используем lamda-выражение, выборка займет много времени. В этом случае лучше использовать linq для получения списка параметров:

var items = (from x in parameters
                join y in myStrings on x.Source equals y
                select x)
            .ToList();
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.