В чем смысл метода расширения .NET 3.5 Enumerable.First()
, когда вы вызываете его в экземпляре коллекции Dictionary
?
Определяет ли набор ключей какой элемент первым, или он просто не определен?
В чем смысл метода расширения .NET 3.5 Enumerable.First()
, когда вы вызываете его в экземпляре коллекции Dictionary
?
Определяет ли набор ключей какой элемент первым, или он просто не определен?
Ну, я считаю, что набор ключей определит, какой элемент первым, но не в четко определенном (или легко предсказать) способе. Другими словами, не предполагайте, что он всегда будет работать одинаково - он небезопасен, поскольку полагается на реализацию хеш-кода, оставаясь тем же самым между прогонами.
EDIT: Я считаю, что на самом деле упорядочение вставки имеет значение, вопреки моим предыдущим идеям. Однако это специфично для реализации (поэтому его можно легко изменить в следующей версии). Я считаю, что с текущей реализацией первая добавленная запись будет первой, если она не была удалена. Если первая добавленная запись удаляется, упорядочение прерывается - это не значит, что самая ранняя запись удалена. Вот пример:
using System;
using System.Collections.Generic;
class Test
{
static void Main(string[] args)
{
var dict = new Dictionary<int, int>();
dict.Add(0, 0);
dict.Add(1, 1);
dict.Add(2, 2);
dict.Remove(0);
dict.Add(10, 10);
foreach (var entry in dict)
{
Console.WriteLine(entry.Key);
}
Console.WriteLine("First key: " + dict.First().Key);
}
}
Результаты 10, 1, 2 и "Первый ключ: 10" - показывая, что последняя добавленная запись заканчивается тем, что возвращается первым.
Тем не менее, я хотел бы еще раз подчеркнуть, что все может измениться между версиями фреймворка.
Если вам нужен первый элемент в словаре, лучше всего использовать SortedDictionary. Я бы подумал, что метод First() просто вернет первый элемент, который находится наверху, но не обязательно первый, который был добавлен.
Я искал какой-то код, который использовал цикл foreach для получения "первого" элемента в объекте словаря. Код предполагает, что это первый, добавленный в словарь.
Первоначально я думал, что метод Dictionary.First() будет более эффективным. Но потом я понял, что все понятие о том, что является первым, может не иметь особого смысла в этом контексте.
The SortedDictionary, который, по словам Эчилона, вероятно, имеет больше накладных расходов и намного большую функциональность, чем мне нужно. Я наклоняюсь, чтобы просто сохранить ключ первого добавленного элемента.
Заказ коллекции Keys
в классе, реализующем Dictionary<TKey, TValue>
, не указан. Поэтому вы не знаете, какое значение First()
будет возвращено.
Но есть причина использовать First()
в любом случае - или, более конкретно, использовать FirstOrDefault()
. Если у вас есть метод, который принимает аргумент IEnumerable<T>
, и вы знаете, что T - тип, значение по умолчанию которого null, your method can use
FirstOrDefault() `, чтобы проверить объект, чтобы увидеть, пуст ли он.
Зачем вам это делать вместо использования Count()
? Использовать отсроченное исполнение. Если вы вызываете FirstOrDefault()
на генераторе, генератор дает один результат и останавливается. Если вы вызываете Count()
в генераторе, генератор должен перечислить в конец списка.
Итак, вы можете написать такую функцию:
bool ListIsEmpty(IEnumerable<string> list)
{
return list.FirstOrDefault() == null;
}
и используйте его следующим образом:
if (!ListIsEmpty(dict.Keys))
{
Console.WriteLine("Dictionary is not empty");
}
if (!ListIsEmpty(dict.Keys.Where(x => x.Contains("foo"))
{
Console.WriteLine("Dictionary has at least one key containing 'foo'.");
}
и знайте, что код выполняет минимальный минимум, который он должен выполнить для принятия этих решений.
Edit:
Я должен указать, что другое предположение, сделанное выше кодом: что IEnumerable<T>
не имеет нуля в качестве своего первого элемента!
Это всегда гарантируется для коллекции Keys
словаря или DataRowCollection
(мой основной вариант использования для LINQ) или для Where()
при запуске в одной из этих коллекций.
Но это не гарантируется для List<string>
или List<DataRow>
. Таким образом, есть определенные обстоятельства, в которых вы хотели бы подумать дважды, прежде чем использовать FirstOrDefault()
.
Я сделал еще несколько копаний и обнаружил, что MSDN предупреждает, что порядок значений и ключей в словаре не указан. Поэтому я считаю, что это означает, что First() может не всегда возвращать то же значение, что и дополнительные значения.