web-dev-qa-db-ja.com

C#には、Vector <T>用のC ++でのサイズ変更のようなList <T>のメソッドがありますか

vector<T>のC++でresize(int newsize)を使用する場合、これは、このsizevectornewsizeに設定され、インデックスが[0..newsize)の範囲で実行されることを意味します。 List<T>のC#で同じことを行うには?
List<T>プロパティCapacityを変更すると、Capacityのみが変更されますが、Countは同じままです。さらに、インデックスは[0..Count)の範囲にあります。手伝ってください。

追伸vector<T> tmptmp.size() == 5が付いていると想像してください。tmp[9]を参照することはできませんが、tmp.resize(10)を使用するとtmp[9]を参照することがあります。 C#では、List<T> tmptmp.Count == 5がある場合、tmp[9]IndexOutOfRangeException)を参照できませんが、tmp.Capacity=10を設定しても、tmp[9]を参照できませんtmp.Countのcozは5のままです。類似点を見つけたいC#でのサイズ変更。

27
nhtrnm

いいえ。ただし、拡張メソッドを使用して独自のメソッドを追加できます。以下はstd::vector<T>::resize()と同じ動作で、同じ時間の複雑さを含みます。唯一の違いは、C++ではvoid resize ( size_type sz, T c = T() )を使用してデフォルトを定義できることと、テンプレートの動作方法は、アクセス可能なパラメーターなしのコンストラクターがないTのデフォルトなしでそれを呼び出す場合に問題ないことです。 。 C#ではそれを行うことができないため、代わりに、デフォルトで使用されていないケースと一致する制約のないメソッドと、それを呼び出す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)のようなものが、C++のベクトルから期待されるものと一致します。ただし、C++ではポインターのベクトルが存在する場合があるのに、C#では参照型のリストが存在することに注意してください。したがって、C++のT()がnullポインターを生成する場合(ポインターであるため)、ここではパラメーターのないコンストラクターを呼び出すと想定しています。そのため、2番目のメソッドを次のように置き換えるのに慣れている動作に近いことがわかるでしょう。

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

これは値の型(パラメーターなしのコンストラクターを呼び出す)と同じ効果がありますが、参照型ではnullで埋められます。この場合、クラス全体を次のように書き換えることができます。

_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>_の違いについてではなく、C++とC#でのポインターの使用方法の違いについてであることに注意してください。

28
Jon Hanna

ちょうど Jon Hannaの答え をもっと読みやすくするために:

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));
        }
    }
}
12
puradox

ごめんなさい。これは何が必要ですか? List.TrimExcess()

2
DarthVader

_List<T>.Capacity_の設定は、std::vector<T>.reserve(..)の使用に似ています。多分List<T>.AddRange(..)はあなたのニーズに合うでしょう。

1
Simon

これが私の解決策です。

_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_または他のnull許容型の代わりに使用され、リストの空の項目を埋めます。 _<T>_のタイプを知っている(参照、値、構造体など)。

追伸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);
}
_