L oop через IEnumerable ничего не возвращает - PullRequest
1 голос
/ 30 января 2020

Я пытаюсь вернуть элемент списка (lookupData), который соответствует определенным c критериям (как определено элементами в массиве lookupKey).

Однако результат не возвращается, если я определить вывод как IEnumerable тип. Переменная «Выход» сбрасывается в конечном l oop, когда i = 2. Почему это не работает?

Я хочу сохранить вывод как IEnumerable вместо List, поскольку он более эффективен.

   var lookupKey = new string[] { "Male", "China" };

   var lookupData = new List<string[]>();
   lookupData.Add(new string[] { "Male", "China" });
   lookupData.Add(new string[] { "Male", "America" });
   lookupData.Add(new string[] { "Female", "UK" });

   IEnumerable<string[]> output = lookupData;

   for (int i = 0; i < 2; i++)
   {
      output = output.Where(x => x[i] == lookupKey[i]);
   }

Ответы [ 5 ]

2 голосов
/ 30 января 2020

Переменная i l oop записывается не так, как вы собираетесь. Решение состоит в том, чтобы ввести локальную переменную внутри l oop:

for (int i = 0; i < 2; i++)
{
    var index = i;
    output = output.Where(x => x[index] == lookupKey[index]);
}

Здесь вы найдете дополнительную информацию о захвате переменных l oop: Захваченная переменная в al oop in C#

1 голос
/ 30 января 2020

Проще говоря, когда вы используете переменную в лямбде, она расширяет область видимости переменной до лямбды / лямбда все еще имеет доступ к i даже после того, как для l oop закончен и ваша ссылка на i установлена в инициализаторе for l oop вышел из области видимости.

Поскольку LINQ-выполнение лямбды действительно происходит только тогда, когда вы запрашиваете результат / перечисляете перечислимое (и это может быть несколько часов спустя), лямбда будет посмотрите значение i, как оно было оставлено для l oop, то есть 2, и это будет означать, что ваша лямбда-индекс испытывает индекс вне диапазона

В последних версиях c# внутреннее поведение foreach l oop был изменен так, что каждая итерация l oop возвращает копию переменной из того, что итерировалось, так что вы должны быть в состоянии изменить ваш for на foreach на lookupKey, и он будет работать как вы ожидать. Тем не менее, это неуклюжий шаблон для чтения и понимания, и я думаю, вам следует подумать о том, чтобы изменить его на что-то вроде:

var output = lookupData.Where(arr => arr.SequenceEquals(lookupKey));

Если набор данных будет большим и будет часто выполняться поиск, рассмотрите возможность использования контейнера, который будет sh элементы вместо этого, потому что сейчас этот метод требует большого числа сравнений строк - количество записей в lookupData, умноженное на количество записей в lookupKey

0 голосов
/ 30 января 2020

Вы ищете логи c не совсем правильно, вам не нужно for l oop, поскольку оно переопределяет критерии where. Вот возможный способ поиска, он вернет IEnumerable<string[]>:

var output = lookupData.Where(g => g[0] == lookupKey[0] && g[1] == lookupKey[1]);
0 голосов
/ 30 января 2020

Используйте List<string[]> вместо IEnumerable<string[]>. Поскольку IEnumerable<string[]> будет выполнять запрос, когда ему нужно получить значения (например, Count () или L oop). Так что в вашем случае после l oop вашего состояния, когда вы попытаетесь l oop над IEnumerable объектом в этот момент, он будет оценивать .Where(x => x[i] == lookupKey[i]). Так что здесь он будет иметь значение i = 3. Это является причиной вашей проблемы.

Если вы используете List<string[]>, тогда он будет вычислять выражение непосредственно внутри для l oop, который вы использовали.

Ваш обновленный код будет выглядеть следующим образом.

var lookupKey = new string[] { "Male", "China" };

var lookupData = new List<string[]>();
lookupData.Add(new string[] { "Male", "China" });
lookupData.Add(new string[] { "Male", "America" });
lookupData.Add(new string[] { "Female", "UK" });

List<string[]> output = lookupData;

for (int i = 0; i < 2; i++)
{
   output = output.Where(x => x[i] == lookupKey[i]).ToList();
}

IEnumerable vs List - Что использовать? Как они работают? Надеюсь, этот ответ может быть полезным.

0 голосов
/ 30 января 2020

Вы можете использовать Where(), All() и Contains() из LINQ:

var output = lookupData
    .Where(data => data.All(item => lookupKey.Contains(item)))

Примечание: , если вы хотите, чтобы ваш результат был List<string[]> вместо IEnumerable<string[]>, добавьте ToList() в конце запроса.

...