Сохраняет ли HashSet порядок вставки? - PullRequest
57 голосов
/ 18 марта 2009

Сохраняет ли коллекция HashSet, представленная в .NET 3.5, порядок вставки при повторении с использованием foreach?

Документация гласит, что коллекция не отсортирована, но ничего не говорит о порядке вставки. В предварительной версии BCL в блоге говорится, что она неупорядочена, но в этой статье говорится, что она предназначена для сохранения порядка вставки. Мое ограниченное тестирование показывает, что порядок сохранен, но это может быть совпадением.

Ответы [ 6 ]

67 голосов
/ 18 марта 2009

На этой странице HashSet MSDN специально написано:

Набор - это коллекция, которая не содержит повторяющихся элементов и элементы которой расположены в произвольном порядке.

39 голосов
/ 18 марта 2009

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

РЕДАКТИРОВАТЬ: Вот контрпример:

using System;
using System.Collections.Generic;

class Test
{
    static void Main()
    {
        var set = new HashSet<int>();

        set.Add(1);
        set.Add(2);
        set.Add(3);
        set.Remove(2);
        set.Add(4);


        foreach (int x in set)
        {
            Console.WriteLine(x);
        }
    }
}

Печать 1, 4, 3, несмотря на то, что 3 были вставлены до 4.

возможно , что если вы никогда не удалите какие-либо элементы, это сохранит порядок вставки. Я не уверен, но я не был бы полностью удивлен. Тем не менее, я думаю, что было бы очень плохо полагаться на это:

  • Это не задокументировано для такой работы, и в документации прямо указано, что она не отсортирована.
  • Я не смотрел на внутренние структуры или исходный код (которого у меня, очевидно, нет) - мне пришлось бы внимательно изучить их, прежде чем делать какие-либо подобные заявления твердым образом.
  • Реализация может очень легко меняться между версиями фреймворка. Полагаться на это было бы все равно, что полагать, что реализация string.GetHashCode не изменилась - что некоторые люди делали еще в .NET 1.1 дней, а потом они обожглись, когда реализация изменила в .NET 2.0. .
7 голосов
/ 18 марта 2009

В документации говорится:

Коллекция HashSet <(Of <(T>)>) не отсортирована и не может содержать повторяющиеся элементы. Если порядок или дублирование элементов для вашего приложения важнее производительности, рассмотрите возможность использования класса List <(Of <(T>)>) вместе с методом Sort.

Поэтому не имеет значения, сохраняет ли он на самом деле порядок элементов в текущей реализации, потому что это не задокументировано как это, и даже если кажется, что это может измениться в любой момент в будущем (даже в исправление к фреймворку).

Вы должны программировать против документированных контрактов , а не подробностей реализации .

2 голосов
/ 18 марта 2009

Нет, хеш-набор не сохранит порядок вставки, по крайней мере, не предсказуемо. Вы можете использовать LinkedHashSet (Java) или его эквивалент. LinkedHashSet сохранит порядок.

Если вы хотите заказать, вам даже не следует использовать набор во-первых ... он не предназначен для упорядоченных элементов, за исключением исключительных случаев.

РЕДАКТИРОВАТЬ: звучит так, как будто я проповедую: - / Извините.

0 голосов
/ 26 апреля 2016

Чтение исходного кода для HashSet.AddIfNotPresent вы можете видеть, что порядок вставки сохраняется при условии, что не было никаких удалений .

Таким образом, new HashSet<string> { "Tom", "Dick", "Harry" } сохраняет порядок, но если затем удалить Дика и добавить Рика, порядок будет ["Том", "Рик", "Гарри"].

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