Как эффективно изменить размер массива значений без бокса, используемого в строке Dictionary ‹, float []›

В приведенном ниже коде страницы определены как

 public SortedDictionary<DateTime, float[]> Pages { get; set; }

Я пытаюсь динамически увеличивать размер этого массива. Может кто подскажет, как увеличить размер самого внутреннего поплавка []?

 var tt = currentContainer.Pages[dateTime];
 Array.Resize<float>(ref tt, currentContainer.Pages.Count + 1);

Ошибка 1

Я попробовал следующий код и получил исключение индекса вне допустимого диапазона

    SortedDictionary<DateTime, float[]> Pages = new SortedDictionary<DateTime,float[]>();
    float[] xx = new float[1];
    xx[0] = 1;
    DateTime tempTime = DateTime.UtcNow;
    Pages.Add(tempTime, xx);
    var tt = Pages[tempTime];
    Array.Resize<float>(ref tt, Pages.Count + 1);
    Pages[tempTime][1] = 2;

Ошибка 2

Ниже приводится ошибка времени компиляции (свойство, индекс или динамический член не могут использоваться в качестве значения ссылки)

    SortedDictionary<DateTime, float[]> Pages = new SortedDictionary<DateTime,float[]>();
    float[] xx = new float[1];
    xx[0] = 1;
    DateTime tempTime = DateTime.UtcNow;
    Pages.Add(tempTime, xx);
    var tt = Pages[tempTime];
    // The line below is different from Fail 1 above ... compile time error
    Array.Resize<float>(ref Pages[tempTime], Pages.Count + 1);
    Pages[tempTime][1] = 2;

Вопрос

Каков наиболее эффективный ответ для изменения размера этого массива?

Изменится ли ответ, если окончательный размер будет 100-200 или 700-900?

Что, если я изменю размер выделения с +1 на +128? .. или больше?


person halfbit    schedule 18.01.2011    source источник
comment
Есть ли причина, по которой вы не используете вместо этого просто SortedDictionary<DateTime, List<float>>? Вам не нужно ничего изменять. Просто вызовите Add () в списке. ???   -  person Brian Genisio    schedule 18.01.2011
comment
Гарантирует ли список или связанный список порядок плавающих элементов? Для меня это очень важно.   -  person halfbit    schedule 18.01.2011
comment
Список ‹T› вызовет множество упаковок / распаковок для моего типа значения с плавающей запятой. Наверное, не лучший выбор   -  person halfbit    schedule 18.01.2011
comment
Использование общих коллекций не приведет к упаковке / распаковке. Когда вы указываете List ‹float›, базовый тип массива List фактически имеет тип float. Использование нестандартной коллекции со слабой типизацией, такой как ArrayList, может вызвать чрезмерное количество упаковок / распаковок. Лучше всего здесь действительно пойти со списком ‹float›.   -  person Wes P    schedule 18.01.2011
comment
Если вы объявите, что список принимает тип float, это не вызовет бокса   -  person Rob    schedule 18.01.2011
comment
Я не понимаю, что MSDN говорит о: List ‹T› vs ArrayList ... кое-что о 500-м элементе: msdn.microsoft.com/en-us/library/6sh2ey19.aspx   -  person halfbit    schedule 18.01.2011
comment
Реализация List ‹T› занимает место в памяти своими дополнительными методами и функциями. Когда список достигает примерно 500 элементов, память, сохраненная при не упаковке / распаковке, превосходит размер реализации. Короче говоря, List ‹T› с 500+ элементами требует меньше памяти для хранения, чем ArrayList с тем же количеством элементов, как хорошо, как сэкономленное время из-за отсутствия упаковать / распаковать.   -  person Rob    schedule 18.01.2011
comment
Короче говоря, можно ли сказать, что ArrayList более эффективен для менее чем 500 объектов типа значения?   -  person halfbit    schedule 18.01.2011
comment
Что касается памяти, то да.   -  person Rob    schedule 18.01.2011


Ответы (5)


Используйте 1_,

Пример,

SortedDictionary<DateTime, List<float>> data;

data = new SortedDictionary<DateTime, List<float>>();

data.Add(DateTime.Now, new List<float>() { 11.4f, 322.3f, 33.5f });

РЕДАКТИРОВАТЬ:

Как получить / установить значения из списка?

List<float> a = new List<float>()
{
  10.2f,20.3f
};

float v1 = a[0];
float v2 = a[1];

Console.WriteLine("{0} {1}", v1, v2);

a[0] = 90.40f;
Console.WriteLine("{0} {1}", a[0],a[1]);
person kv-prajapati    schedule 18.01.2011
comment
Гарантирует ли список или связанный список порядок размещения чисел с плавающей запятой? Для меня это очень важно .. - person halfbit; 18.01.2011
comment
+1 с помощью списка. И List, и LinkedList сохраняют порядок (в отличие от Dictionary и HashSet). Список больше похож на массив ... - person Alexei Levenkov; 18.01.2011
comment
+1 Брайан. @ makerofthings7: представляет собой строго типизированный список объектов, к которым можно получить доступ по индексу. - person kv-prajapati; 18.01.2011
comment
Список ‹T› вызовет множество упаковок / распаковок для моего типа значения с плавающей запятой. Наверное, не лучший выбор. - person halfbit; 18.01.2011
comment
@ makerofthings7 - Я думаю, вы неправильно поняли использование List ‹T›. - person kv-prajapati; 18.01.2011
comment
См. Здесь для получения дополнительных объяснений. stackoverflow.com/questions/4403055/ - person Divi; 18.01.2011
comment
Спасибо, Диви, читаю сейчас. См. Ссылку, которую я разместил под вопросом, касающимся MSDN и упоминания объекта 500. Это меня сбивает. - person halfbit; 18.01.2011
comment
@ Divi- Все это связано с использованием стека / кучи (памяти). - person kv-prajapati; 18.01.2011
comment
Итак, стал бы я придиркой, если бы выбрал ArrayList, если в среднем у меня меньше 300 объектов? Преимущество ссылки MSDN сосредоточено на использовании памяти или производительности? - person halfbit; 18.01.2011
comment
Если вы перейдете в ArrayList, вы начнете упаковывать / распаковывать. Придерживайтесь List<T>. Такой уровень оптимизации необходим только в том случае, если вы точно знаете, что код является узким местом. List<T> - ваш друг. - person Brian Genisio; 18.01.2011

Во-первых, рассмотрите возможность использования Dictionary<DateTime, List<Float>> вместо массива. Поскольку все ваши примеры кода включают увеличение размера массива на 1, это означает, что вы собираетесь многократно изменять размер массивов, чтобы достичь их окончательного размера. Если это так, то будет лучше выбрать контейнер, который может расширяться сам по себе и может делать это эффективно.

Во-вторых, все ваши примеры используют массивы длиной на единицу больше, чем количество элементов в словаре. Это необычные отношения, вы уверены, что Dictionary<DateTime, (some group of floats)> - подходящий контейнер?

Тем не менее, вот как изменить размер массива внутри словаря.

SortedDictionary<DateTime, float[]> Pages = new SortedDictionary<DateTime,float[]>();
DateTime date = DateTime.UtcNow;

float[] arr = Pages[date];
Array.Resize<float>(ref arr, arr.Length + 1);
Pages[date] = arr; // [] overwrites the old value, unlike Add().
person David Yaw    schedule 18.01.2011
comment
Будут ли частые операции изменения размера оказывать давление на стек или кучу в этом случае? - person halfbit; 18.01.2011
comment
В куче. Или, более конкретно, вы делаете дополнительную работу для сборщика мусора. - person David Yaw; 18.01.2011
comment
Основываясь на том, что я вижу и читаю, я сравниваю ArrayList, List ‹T› и этот метод. Я проведу некоторый анализ, чтобы увидеть, есть ли у меня более 500 элементов в массиве, чтобы оправдать список ‹T› - person halfbit; 18.01.2011
comment
Чтобы ответить на ваш вопрос, да, я думаю, что это правильный выбор контейнера для моей реализации. Я собираю данные в определенный момент времени. Каждая точка данных является плавающей точкой. Положение поплавка в массиве придает ему смысл. - person halfbit; 18.01.2011
comment
После тестирования это кажется наиболее производительным решением по сравнению со списком ‹T›, если я увеличу размер выделения с +1 до +10 и сохраню объекты меньше 300. - person halfbit; 18.01.2011
comment
Если вы собираете данные в определенный момент времени, почему Dictionary<DateTime, float> это не подходит? Если у вас есть датчики ‹n›, не будет ли длина массива постоянной ‹n›, а не изменяющейся? (Я не хочу об этом говорить, это просто довольно необычная структура данных.) - person David Yaw; 18.01.2011

Array.Resize (ref tt, Pages.Count + 1); Страницы [tempTime] = tt;

person Alexei Levenkov    schedule 18.01.2011
comment
Будут ли частые операции изменения размера оказывать давление на стек или кучу в этом случае? - person halfbit; 18.01.2011
comment
Список ‹float› гораздо лучше работает при изменении размера по отношению к куче / процессору. Если вы часто вызываете Array.Resize (особенно если вы увеличиваете его на 1, как в вашем примере), это окажет серьезное давление на выделение памяти и ЦП для копирования большого количества данных. - person Alexei Levenkov; 18.01.2011

Вместо того

общедоступный SortedDictionary ‹DateTime, float []> Pages {get; установленный; },

вы могли бы использовать

общедоступный SortedDictionary ‹DateTime, List‹ float >> Pages {get; установленный; },

поэтому вам не придется изменять размер, и если вы все еще хотите получить к нему доступ как к массиву, вы всегда можете использовать ToArray () класса List.

Надеюсь это поможет

person Divi    schedule 18.01.2011
comment
Список ‹T› вызовет множество упаковок / распаковок для моего типа значения с плавающей запятой. Наверное, не лучший выбор. - person halfbit; 18.01.2011
comment
Когда дело доходит до коллекций, дженерики позволяют избежать упаковки за счет использования реальных массивов T []. Например, List ‹T› использует массив T [] для хранения своего содержимого. stackoverflow.com/questions/4403055/ Массив, из Конечно, это ссылочный тип, поэтому он (в текущей версии CLR, yada yada) хранится в куче. Но поскольку это T [], а не object [], элементы массива могут храниться напрямую: то есть они все еще находятся в куче, но они находятся в куче в массиве вместо того, чтобы быть помещенными в коробку и иметь массив содержат ссылки на боксы. - person Divi; 18.01.2011
comment
+1 за ваши ссылки и комментарии к этому посту в целом ... Спасибо! - person halfbit; 18.01.2011

Я бы использовал список, как предложено в других ответах. Причина, по которой вы не можете изменить массив с помощью Array.Resize(), заключается в том, что он копирует массив в новый массив, для которого он возвращает ссылку для (Вывод отражателя ниже), поэтому, если вы не повторно присвоите новое значение Pages[tempTime], вы находитесь вне удача.

[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public static void Resize<T>(ref T[] array, int newSize)
{
    if (newSize < 0)
    {
        throw new ArgumentOutOfRangeException("newSize", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
    }
    T[] sourceArray = array;
    if (sourceArray == null)
    {
        array = new T[newSize];
    }
    else if (sourceArray.Length != newSize)
    {
        T[] destinationArray = new T[newSize];
        Copy(sourceArray, 0, destinationArray, 0, (sourceArray.Length > newSize) ? newSize : sourceArray.Length);
        array = destinationArray;
    }
}
person BrokenGlass    schedule 18.01.2011