Есть ли в С# метод для List <T>, как изменение размера в С++ для вектора <T>

Когда я использую resize(int newsize) в С++ для vector<T>, это означает, что size этого vector установлен в newsize, а индексы работают в диапазоне [0..newsize). Как сделать то же самое в С# для List<T>?
Изменение свойства List<T> Capacity изменяет только Capacity, но оставляет Count тем же, и, кроме того, индексы все еще находятся в диапазоне [0..Count). Помогите мне, пожалуйста.

P.S. Представьте, что у меня есть vector<T> tmp с tmp.size() == 5, я не могу ссылаться на tmp[9], но когда я использую tmp.resize(10), я могу обратиться к tmp[9]. В С#, если у меня есть List<T> tmp с tmp.Count == 5, я не могу ссылаться на tmp[9] (IndexOutOfRangeException), но даже когда я устанавливаю tmp.Capacity=10, я не буду ссылаться на tmp[9] coz tmp.Count еще 5. Я хочу найти некоторую аналогию с изменением размера в С#.

Ответы

Ответ 1

Нет, но вы можете использовать методы расширения, чтобы добавить свои собственные. Следующее имеет такое же поведение, как std::vector<T>::resize(), включая ту же сложность времени. Единственное отличие состоит в том, что в С++ мы можем определить значение по умолчанию с void resize ( size_type sz, T c = T() ), а способ работы с шаблонами означает, что это прекрасно, если мы будем называть его без значения по умолчанию для T, у которого нет доступного конструктора без параметров. В С# мы не можем этого сделать, поэтому вместо этого мы должны создать один метод без ограничения, который соответствует случаю, не используемому по умолчанию, а другой с ограничением where new(), который вызывает его.

public static class ListExtra
{
    public static void Resize<T>(this List<T> list, int sz, T c)
    {
        int cur = list.Count;
        if(sz < cur)
            list.RemoveRange(sz, cur - sz);
        else if(sz > cur)
        {
            if(sz > list.Capacity)//this bit is purely an optimisation, to avoid multiple automatic capacity changes.
              list.Capacity = sz;
            list.AddRange(Enumerable.Repeat(c, sz - cur));
        }
    }
    public static void Resize<T>(this List<T> list, int sz) where T : new()
    {
        Resize(list, sz, new T());
    }
}

Теперь подобные myList.Resize(23) или myList.Resize(23, myDefaultValue) будут соответствовать ожиданиям от вектора С++. Я бы заметил, что иногда, когда с С++ у вас будет вектор указателей, в С# у вас будет список некоторых ссылочных типов. Следовательно, в случаях, когда С++ T() создает нулевой указатель (потому что это указатель), здесь мы ожидаем, что он вызовет конструктор без параметров. По этой причине вы можете найти его ближе к поведению, которое вы использовали для замены второго метода:

  public static void Resize<T>(this List<T> list, int sz)
  {
      Resize(list, sz, default(T));
  }

Это оказывает такое же влияние на типы значений (calllessless constructor), но с ссылочными типами он заполняет нулями. В этом случае мы можем просто переписать весь класс следующим образом:

public static class ListExtra
{
    public static void Resize<T>(this List<T> list, int sz, T c = default(T))
    {
        int cur = list.Count;
        if(sz < cur)
            list.RemoveRange(sz, cur - sz);
        else if(sz > cur)
            list.AddRange(Enumerable.Repeat(c, sz - cur));
    }
}

Обратите внимание, что речь идет не о различиях между std::vector<T> и List<T>, а о различиях в том, как указатели используются в С++ и С#.

Ответ 2

Просто чтобы сделать Jon Hanna answer более читаемым:

public static class ListExtras
{
    //    list: List<T> to resize
    //    size: desired new size
    // element: default value to insert

    public static void Resize<T>(this List<T> list, int size, T element = default(T))
    {
        int count = list.Count;

        if (size < count)
        {
            list.RemoveRange(size, count - size);
        }
        else if (size > count)
        {
            if (size > list.Capacity)   // Optimization
                list.Capacity = size;

            list.AddRange(Enumerable.Repeat(element, size - count));
        }
    }
}

Ответ 3

извините. это то, что вам нужно? List.TrimExcess()

Ответ 4

Настройка List<T>.Capacity похожа на использование std::vector<T>.reserve(..). Возможно, List<T>.AddRange(..) соответствует вашим потребностям.

Ответ 5

Разве вы не читали в MSDN: -

Список представляет собой изменяемую по размеру коллекцию элементов. Списки могут быть построены несколько способов, но наиболее полезным классом является List. Это позволяет вам чтобы строго указать ваш список, включает в себя все необходимые функциональность для работы с коллекциями и может быть легко поиск.

Далее: -

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

Емкость всегда больше или равна Count. Если граф превышает Производительность при добавлении элементов увеличивает емкость на автоматически перераспределяя внутренний массив перед копированием старого элементы и добавление новых элементов.

Ответ 6

Это мое решение.

private void listResize<T>(List<T> list, int size)
{
   if (size > list.Count)
      while (size - list.Count > 0)
         list.Add(default<T>);    
   else if (size < list.Count)
      while (list.Count - size > 0)
         list.RemoveAt(list.Count-1);
}

Когда значения size и list.Count совпадают, нет необходимости изменять размер списка.

Параметр default(T) используется вместо null, "", 0 или других типов с нулевым значением для заполнения пустого элемента в списке, потому что мы не знаем, какой тип <T> ( ссылка, значение, структура и т.д.).

P.S. Я использовал циклы for вместо циклов while, и я столкнулся с проблема. Я не всегда имел размер списка, о котором я просил. Это было меньше. Любые мысли, почему?

Проверьте это:

private void listResize<T>(List<T> list, int size)
{
   if (size > list.Count)
      for (int i = 0; i <= size - list.Count; i++)
         list.Add(default(T));
   else if (size < list.Count)
      for (int i = 0; i <= list.Count - size; i++)
         list.RemoveAt(list.Count-1);
}

Ответ 7

Список не имеет конечного размера.

Есть ли причина, по которой размер имеет значение для вас?

Возможно, массив или словарь ближе к вашим требованиям