Enumerable.ElementAt vs foreach - PullRequest
       3

Enumerable.ElementAt vs foreach

1 голос
/ 06 октября 2010

У меня есть словарь, который мне нужно обновлять входящими данными, после анализа входящих данных я должен проверить, есть ли какие-либо записи в словаре, которых нет во входящих данных (входящие данные, когда анализируются, являются списком и мне нужно сопоставить его с записями словаря).

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

Я хотел понять, что это повлияет на время выполнения. Я хочу понять, каков порядок работы ElementAt. * ​​1005 *

Ответы [ 6 ]

7 голосов
/ 06 октября 2010

ElementAt полезно, если вам нужно предоставить семантику индексирования и не можете гарантировать, что семантика индексирования будет доступна в базовом перечислении. Он использует индексирование O (1), когда перечисление действует как IList<T> (который включает в себя список и массивы), но в противном случае это O (n) *, что позволяет использовать его в последовательности по всему, что идет от O ( n) операция будет со списком O (n * n).

Если, однако, вы получили копию ключей с dict.Keys.ToList(), вы могли бы безопасно foreach через это, поскольку она не будет изменена при изменении вашего словаря.

Что непонятно, так это то, почему вы не просто заменяете старый словарь новым, что снова будет значительно быстрее (простое назначение ссылок).

* Обновление: в версии linq .NET Core существует больший диапазон случаев, когда ElementAt() - это O (1), например, результаты Select(), выполненные на IList<T>. Также OrderBy(…).ElementAt(…) теперь является O (n), а не O (n log n), поскольку объединенная последовательность превращается в быстрый выбор, а не в быструю сортировку с последующей итерацией.

3 голосов
/ 06 октября 2010

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

var dict = new Dictionary<int, string>
{ 
    {3, "kuku" },
    {1, "zOl"}
};

var newKeys = new List<int> { 1, 2, 4 };

var toRemove = dict.Keys.Except(newKeys).ToList();

foreach (var k in toRemove)
    dict.Remove(k);
2 голосов
/ 06 октября 2010

Except() похоже, что это будет работать здесь:

Dictionary<int, string> dict = new Dictionary<int, string>
{ 
    {3, "kuku" },
    {1, "zOl"}
};

IEnumerable<int> data = new List<int> { 1, 2, 4 };

IEnumerable<int> toRemove = dict.Keys.Except(data);

foreach(var x in toRemove)
    dict.Remove(x);
2 голосов
/ 06 октября 2010

ElementAt() действительно использует перечислитель, как указано, поэтому, если вы хотите самый быстрый доступ к индексу, вы должны использовать массив. Конечно, это происходит по цене фиксированной длины, но если размер массива не меняется постоянно, вполне возможно, что Array.Resize() может быть путь.

1 голос
/ 06 октября 2010

Я думаю, что ElementAt() использует перечислитель, чтобы добраться до требуемого элемента.

Это будет так же, как:

object returnedElement = null;
int i = 0;
foreach (var obj in dictionary.Keys)
{
   if (i++ == at)
    {
      returnedElement = obj;
      break;
    }
}
0 голосов
/ 06 октября 2010

Вы можете получить словарь соответствующих записей в target (Dictionary) и source (List) следующим образом:

using System;
using System.Collections.Generic;
using System.Linq;

Dictionary<string, string> target = new Dictionary<string, string>();
List<string> source = new List<string>();
target.Add("a", "this is a");
target.Add("b", "this is b");
source.Add("a");
source.Add("c");

target = Enumerable.Select(target, n => n.Key).
    Where(n => source.Contains(n)).ToDictionary(n => n, k => target[k]);

Мне не ясно, хотите ли вы включать новые записи из Списка в Словарь - если да, я не уверен, какими будут значения новых записей, если у вас есть только Список новых входящих данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...