Добавить элемент в конец списка
Как добавить элемент в конец списка в ReasonML (эквивалент Array.concat
в JavaScript)?
2 ответа
Хотя ответ Нейла технически верен, в нем скрываются некоторые детали, которые вы, возможно, захотите рассмотреть, прежде чем добиваться append
; в частности, что добавление элемента в начало списка очень дешево, добавление элемента в конец очень дорого.
Чтобы понять почему, давайте посмотрим, как список определяется и создается. (Концептуальное) определение списка:
type list('a) = Cons('a, list('a)) | Nil;
где Nil
представляет конец списка (и сам по себе пустой список) и Cons
представляет узел в списке, содержащий элемент типа 'a
и указатель на остальную часть списка (list('a)
).
Если бы мы убрали весь синтаксический сахар и каждую вспомогательную функцию, вам пришлось бы создать список следующим образом:
let myList = Cons(1, Cons(2, Cons(3, Nil)));
Чтобы добавить элемент в начало этого списка, мы создаем узел, содержащий наш новый элемент и указатель на старый список:
let myBiggerList = Cons(0, myList);
Это точно так же, как делать [0, ...myList]
, Если myList
может измениться, мы не сможем сделать это, конечно, но мы знаем, что это не так, поскольку списки неизменны. Это делает это очень дешевым, и по той же причине так же дешево обходиться без головы, поэтому вы обычно будете видеть функции обработки списков, реализованные с использованием рекурсии, например:
let rec map = f =>
fun | [] => []
| [x, ...xs] => [f(x), ...map(f, xs)];
Хорошо, тогда почему так дорого добавить элемент в конец списка? Если вы посмотрите на myList
добавление элемента в конец означает замену финального Nil
с, скажем, Cons(4, Nil)
, Но тогда нам нужно заменить Cons(3, ...)
так как это указывает на старое Nil
, а также Cons(2, ...)
потому что это указывает на старое Cons(3, ...)
и так далее по всему списку. И вы должны делать это каждый раз, когда добавляете элемент. Это быстро складывает.
Так что вы должны сделать вместо этого?
Если вы добавляете в конец и либо просто просматриваете его, либо всегда удаляете элементы с конца, как вы часто это делаете в JavaScript, вы, скорее всего, можете просто изменить свою логику. Вместо того, чтобы добавлять и снимать конец, добавляйте и снимайте начало.
Если вам действительно нужна структура данных FIFO, в которой элементы вставляются с одной стороны, а с другой - снимаются, рассмотрите возможность использования очереди. В общем, взгляните на это сравнение эксплуатационных характеристик стандартных контейнеров.
Или, если это все немного, и вы действительно хотите сделать это так, как вы привыкли к JavaScript, просто используйте array
вместо list
, Все функции, с которыми вы знакомы, вы найдете в Js.Array
модуль
Ты можешь использовать List.append
или @
оператор, который является сокращением для List.append
,
let lstA = [ 1 ];
let lstB = lstA @ [ 2 ];
let lstC = List.append(lstB, [ 3 ]);
Вот документация для методов List: https://reasonml.github.io/api/List.html
Смотрите ссылку на игровую площадку здесь: https://reasonml.github.io/en/try.html?reason=DYUwLgBMDOYIIQLwQNoQIwQLoG4BQokMYAQklLAgAKoQBM2+hFYAwuQDICWsAdAIYAHQSAB2AEwAUxEgBpaAZmwBKfEA