Есть ли способ добавления хвоста в массив, который более эффективен, чем добавление в F #?
В настоящее время я пытаюсь создать программу, в которой у меня есть рекурсивная функция, которая для каждого цикла добавляет один новый элемент к массиву, который он строит. Я не хотел использовать функцию append много раз, потому что моя функция должна делать большое количество циклов, и я пришел к изучению из предыдущего опыта, что функция append в целом занимает много времени. Я пытался повсюду искать функцию, которая просто добавляет один элемент в хвост массива, но я не нашел ничего подобного. Поэтому я думал, что попрошу здесь.
Итак, мой вопрос в основном: "Есть ли более эффективный способ добавления одного элемента в конец массива, чем с помощью добавления?"
Обновлен с новым вопросом относительно предыдущего
Итак, я использовал список вместо этого, вставив каждый новый элемент в качестве главы и вернул список, когда функция была закончена. Это сделало функцию примерно в 70 раз быстрее. Но проблема остается, поскольку у меня есть другая функция, которая делает почти то же самое, что стало примерно в 4 раза медленнее, увеличивая общее время для моей основной функции. Функции очень похожи. Первая функция (та, которая стала намного быстрее) создает ints, добавляя каждый новый int в список. Вторая функция (та, которая стала намного медленнее) создает объект, добавляя каждый новый объект в список. У кого-нибудь есть идея, почему одна функция стала намного быстрее, а другая стала намного медленнее?
Ответы
Ответ 1
ResizeArray - более эффективная структура данных для этой задачи, например:
let filterRange predicate (i, j) =
let results = ResizeArray(j-i+1)
for k = i to j do
if predicate k then results.Add(k)
results.ToArray()
Модуль resizeArray из F # PowerPack обеспечивает высокое качество функции для функционального управления ResizeArray
. Однако будьте осторожны, что эти функции создают новые экземпляры ResizeArray
, которые делают их менее эффективными, чем методы .NET.
Существенно функциональная альтернатива - использовать список в качестве аккумулятора, добавлять элементы к аккумулятору, отменить его (если порядок имеет значение) и преобразовать в массив в конце:
let filterRange predicate (i, j) =
let rec loop k acc =
if k = j+1 then acc
elif predicate k then loop (k+1) (k::acc)
else loop (k+1) acc
loop i [] |> List.rev |> Array.ofList
Ответ 2
Я бы предложил использовать список вместо массива. Если вам действительно нужен конечный результат в массиве, вы можете преобразовать список в массив в конце процесса - он все равно будет быстрее.
Ответ 3
Нет. Возможно, вы захотите использовать другую структуру данных.