Есть ли способ добавления хвоста в массив, который более эффективен, чем добавление в 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

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