"DynamicArray" (Data Structure)
"DynamicArray"
represents a dynamically extensible array where the elements are general expressions.
Details
- An extensible array is useful for continuously appending elements, as well as for efficient element extraction and updating.
-
CreateDataStructure["DynamicArray"] create a new empty "DynamicArray" CreateDataStructure["DynamicArray",elems] create a new "DynamicArray" containing elems Typed[x,"DynamicArray"] give x the type "DynamicArray" - For a data structure of type "DynamicArray", the following operations can be used:
-
ds["Append",x] append x to ds time: O(1) ds["Copy"] return a copy of ds time: O(n) ds["Drop",i] drop the i
part of dstime: O(n) ds["DropAll"] drop all the elements from ds time: O(n) ds["DropLast"] drop the last element of ds time: O(1) ds["Elements"] return a list of the elements of ds time: O(n) ds["EmptyQ"] True, if ds has no elements time: O(1) ds["Fold",fun] apply fun to the elements of ds, accumulating a result time: O(n) ds["Fold",fun,init] apply fun to the elements of ds, starting with init, accumulating a result time: O(n) ds["Insert",x,i ] insert x into ds at position i time: O(1) ds["JoinBack",elems ] join elems to the back of ds time: O(nelems) ds["Length"] the number of elements stored in ds time: O(1) ds["Part",i] give the i
part of dstime: O(1) ds["SetPart",i,elem] update the i
part of dstime: O(1) ds["SwapPart",i,j] swap the i
and j
parts of dstime: O(1) ds["Visualization"] return a visualization of ds time: O(n) - The following functions are also supported:
-
dsi===dsj True, if dsi equals dsj ds["Part",i]=val set i
element of ds to valFullForm[ds] full form of ds Information[ds] information about ds InputForm[ds] input form of ds Length[ds] the length of the array Normal[ds] convert ds to a normal expression
Examples
open all close allBasic Examples (2)
A new "DynamicArray" can be created with CreateDataStructure:
ds = CreateDataStructure["DynamicArray"]ds["Append", f[1]]ds["Length"]ds["Part", 1]ds["Part", 1] = f[2]ds["Part", 1]Return an expression version of ds:
Normal[ds]ds = CreateDataStructure["DynamicArray"];
Do[ds["Append", i], {i, 1000}]A visualization of the data structure can be generated:
ds["Visualization"]ds["Fold", Plus, 0]Scope (18)
Information (1)
A new "DynamicArray" can be created with CreateDataStructure:
ds = CreateDataStructure["DynamicArray"]Information about the data structure ds:
Information[ds]Creation (2)
Create an empty "DynamicArray":
CreateDataStructure["DynamicArray"]Create a "DynamicArray" with initial values:
CreateDataStructure["DynamicArray", {x, y, z}]Operations (15)
"Append" (1)
Append an element to a "DynamicArray":
ds = CreateDataStructure["DynamicArray"];
ds["Append", f[x, y]]Get the contents of the array:
Normal[ds]"Copy" (1)
Create a "DynamicArray" with initial values:
ds = CreateDataStructure["DynamicArray", {1, 2, 3}]ds1 = ds["Copy"]The contents of both arrays are the same:
{Normal[ds], Normal[ds1]}Modifying the copy will not affect the original array:
ds1["Append", 42];
{Normal[ds], Normal[ds1]}"Drop" (1)
Create a "DynamicArray" with initial values:
ds = CreateDataStructure["DynamicArray", Range[10]];
ds["Visualization"]Drop the fifth element of the array:
ds["Drop", 5]ds["Visualization"]"DropAll" (1)
Create a "DynamicArray":
ds = CreateDataStructure["DynamicArray", Range[10]];
ds["Visualization"]Drop all the elements of the array:
ds["DropAll"]Length[ds]"DropLast" (1)
Create a "DynamicArray" with initial values:
ds = CreateDataStructure["DynamicArray", Range[10]];
ds["Visualization"]Drop the last element and get the dropped value:
ds["DropLast"]ds["Visualization"]"Elements" (1)
Create a "DynamicArray" with initial values:
ds = CreateDataStructure["DynamicArray", Range[10]];
ds["Visualization"]ds["Elements"]Normal returns the same list:
Normal[ds]"EmptyQ" (1)
Test whether a "DynamicArray" is empty or not:
ds = CreateDataStructure["DynamicArray"];
ds["EmptyQ"]After appending an element, the array is no longer empty:
ds["Append", x];
ds["EmptyQ"]"Fold" (1)
Create a "DynamicArray" with initial values:
ds = CreateDataStructure["DynamicArray", Range[10]]Combine all elements of the array using Plus, producing their total sum:
ds["Fold", Plus]You can also specify an initial value to start the accumulation:
ds["Fold", Plus, 42]"Insert" (1)
Create a "DynamicArray" with initial values:
ds = CreateDataStructure["DynamicArray", Range[8]]Insert an element at the specified position:
ds["Insert", x, 5]Visualize the contents of the array:
ds["Visualization"]"JoinBack" (1)
Create a "DynamicArray" with initial values:
ds = CreateDataStructure["DynamicArray", Range[5]]Append multiple elements to the end of the array:
ds["JoinBack", Range[6, 10]]ds["Visualization"]"Length" (1)
Create a "DynamicArray" with initial values:
ds = CreateDataStructure["DynamicArray", Range[5]]Get the number of elements in the array:
ds["Length"]Length gives the same value:
Length[ds]"Part" (1)
Create a "DynamicArray" with initial values:
ds = CreateDataStructure["DynamicArray", Range[10]]Get the fifth element of the array:
ds["Part", 5]"SetPart" (1)
Create a "DynamicArray" with initial values:
ds = CreateDataStructure["DynamicArray", Range[10]]Set the fifth element of the array to a different value:
ds["SetPart", 5, x]ds["Visualization"]The following syntax is also valid:
ds["Part", 6] = y;
ds["Visualization"]"SwapPart" (1)
Create a "DynamicArray" with initial values:
ds = CreateDataStructure["DynamicArray", Range[10]]Swap the values of the elements in the fifth and sixth positions:
ds["SwapPart", 5, 6]ds["Visualization"]"Visualization" (1)
Create a "DynamicArray" with initial values:
ds = CreateDataStructure["DynamicArray", Range[10]]Visualize the contents of the array:
ds["Visualization"]Applications (11)
Reverse (1)
A simple function that carries out an in-place reverse of a "DynamicArray":
ArrayReverse[ ds : DataStructure["DynamicArray", _]] :=
Module[{start = 0, end = ds["Length"] + 1},
While[++start < --end,
ds["SwapPart", start, end]
];
ds];A sample data structure to use:
ds = CreateDataStructure["DynamicArray", {9, 2, 7, 0}];Normal[ArrayReverse[ds]]Bubble Sort (1)
Bubble sort is a simple sorting algorithm that is easy to code but typically has poor performance:
BubbleSort[ ds : DataStructure["DynamicArray", _]] :=
Module[{repeat = True},
While[repeat,
repeat = False;
Do[
If[ds["Part", i] > ds["Part", i + 1],
ds["SwapPart", i, i + 1];
repeat = True];, {i, ds["Length"] - 1}]];
ds];A sample data structure to use:
ds = CreateDataStructure["DynamicArray", {9, 2, 7, 0}];Normal[BubbleSort[ds]]The data structure is sorted in place:
Normal[ds]Insertion Sort (1)
Insertion sort is a simple sorting algorithm that is easy to code and typically has poor performance for large arrays, but can be useful for small arrays:
InsertionSort[ ds : DataStructure["DynamicArray", _]] :=
Module[{len, i, j},
len = ds["Length"];
Do[j = i;
While[j > 1 && ds["Part", j - 1] > ds["Part", j], ds["SwapPart", j, j - 1];j--], {i, 2, len}];
ds]A sample data structure to use:
ds = CreateDataStructure["DynamicArray", {9, 2, 7, 0}];Normal[InsertionSort[ds]]The data structure is sorted in place:
Normal[ds]Quicksort (1)
Quicksort is an efficient sorting algorithm. This basic implementation uses nested functions:
Quicksort[ ds : DataStructure["DynamicArray", _]] :=
Module[{partitionFun, sortFun},
partitionFun =
Function[{low, high},
Module[{pivot = ds["Part", high], i = low, j},
Do[
If[ds["Part", j] ≤ pivot,
ds["SwapPart", i, j];i = i + 1],
{j, low, high - 1}];
ds["SwapPart", i, high];
i]];
sortFun = Function[{low, high},
If[low < high,
Module[{p = partitionFun[low, high]},
sortFun[low, p - 1];
sortFun[p + 1, high]
] ]];
sortFun[1, ds["Length"]];
ds]A sample data structure to use:
ds = CreateDataStructure["DynamicArray", {9, 2, 7, 0}];Normal[Quicksort[ds]]The data structure is sorted in place:
Normal[ds]Merge Sort (1)
Merge sort is an efficient sorting algorithm. This is a simple implementation that uses a workspace:
MergeSort[ ds : DataStructure["DynamicArray", _]] :=
MergeSortSplit[ds["Copy"] , 1, ds["Length"] + 1, ds]MergeSortSplit[ b_, start_, end_, a_] :=
Module[{mid},
If[end - start > 1,
mid = Quotient[end + start, 2];
MergeSortSplit[a, start, mid, b];
MergeSortSplit[a, mid, end, b];
MergeSortJoin[ b, start, mid, end, a]
];
a]MergeSortJoin[ a_, start_, mid_, end_, b_] :=
Module[{i = start, j = mid, k},
Do[
If[i < mid && (j ≥ end || a["Part", i] ≤ a["Part", j]),
b["Part", k] = a["Part", i];i++,
b["Part", k] = a["Part", j];j++],
{k, start, end - 1}];
]A sample data structure to use:
ds = CreateDataStructure["DynamicArray", {9, 2, 7, 0}];Normal[MergeSort[ds]]The data structure is sorted in place:
Normal[ds]Heapsort (1)
Heapsort is an efficient sorting algorithm that works in place by constructing a heap:
Heapsort[ds : DataStructure["DynamicArray", _]] :=
Module[{len = ds["Length"]},
Do[Heapify[ds, ii], {ii, Quotient[len, 2], 1, -1}];
ds
]Heapify[p : DataStructure["DynamicArray", _], k_Integer] := Module[{i = k, l, n = p["Length"]}, While[(l = 2 i) ≤ n, If[(l < n) && (p["Part", l] > p["Part", l + 1]), l++];
If[p["Part", i] > p["Part", l], p["SwapPart", l, i];
i = l, i = n + 1];];]A sample data structure to use:
ds = CreateDataStructure["DynamicArray", {9, 2, 7, 0}];The elements are sorted in place:
Heapsort[ds];
Normal[ds]Timsort (1)
Timsort is a hybrid and efficient sorting algorithm:
Timsort[ds : DataStructure["DynamicArray", _]] :=
Module[{blockSize = 32, len = ds["Length"], size, mid, right},
Do[InsertionWorker[ds, ii, Min[ii + 32, len]], {ii, 1, len, blockSize}];
size = blockSize;
While[size < len,
Do[
mid = left + size;
right = Min[left + 2 * size, len];
MergeWorker[ds, left, mid, right]
,
{left, 1, len, 2 * size}
];
size *= 2
];
]InsertionWorker[ ds : DataStructure["DynamicArray", _], left_, right_] :=
Module[{i, j},
Do[j = i;
While[j > left && ds["Part", j - 1] > ds["Part", j], ds["SwapPart", j, j - 1];j--], {i, left, right}];
ds]MergeWorker[ b_, start_, mid_, end_] :=
Module[{a, i = start, j = mid, k},
a = b["Copy"];
Do[
If[i < mid && (j ≥ end || a["Part", i] ≤ a["Part", j]),
b["Part", k] = a["Part", i];i++,
b["Part", k] = a["Part", j];j++],
{k, start, end - 1}];
]A sample data structure to use:
ds = CreateDataStructure["DynamicArray", {9, 2, 7, 0}];The elements are sorted in place:
Timsort[ds];
Normal[ds]Fisher–Yates Shuffle (1)
The Fisher–Yates shuffle generates a random permutation of a finite sequence:
FisherYatesShuffle[ ds : DataStructure["DynamicArray", _]] := (
Do[
ds["SwapPart", i, RandomInteger[{1, i}]],
{i, ds["Length"] - 1, 1, -1}
];
ds
);A sample array to use for the shuffle:
ds = CreateDataStructure["DynamicArray", {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100} ];Normal[FisherYatesShuffle[ds]]Palindrome (1)
An array is a palindrome if it is symmetric around the middle:
IsPalindrome[ ds : DataStructure["DynamicArray", _]] :=
Module[{start = 0, end = ds["Length"] + 1},
While[++start < --end,
If[ds["Part", start] =!= ds["Part", end],
Return[False]
]
];
True];ds = CreateDataStructure["DynamicArray", {9, 2, 7, 0}];
IsPalindrome[ds]ds = CreateDataStructure["DynamicArray", {9, 2, 2, 9}];
IsPalindrome[ds]Quickselect (1)
Quickselect is a selection algorithm related to the Quicksort algorithm. It returns the k
smallest element in a list:
Quickselect[ds : DataStructure["DynamicArray", _], k_] :=
QuickselectWorker[ds, 1, ds["Length"], k];QuickselectWorker[ds_, low0_, high0_, k_] :=
Module[{pivotIdx, low = low0, high = high0},
While[True,
If[low === high, Return[ds["Part", low]]];
pivotIdx = SelectPartition[ds, low, high];
Which[
k === pivotIdx, Return[ds["Part", k]],
k < pivotIdx, high = pivotIdx - 1,
True, low = pivotIdx + 1
]
]
];SelectPartition[ds_, low_, high_] :=
Module[{pivot = ds["Part", high], i = low, j},
Do[
If[ds["Part", j] ≤ pivot,
ds["SwapPart", i, j];i = i + 1],
{j, low, high - 1}];
ds["SwapPart", i, high];
i];A sample data structure to use:
ds = CreateDataStructure["DynamicArray", {9, 2, 7, 0}];The third smallest element is 7:
Quickselect[ds, 3]Heap (1)
A heap is a tree-based data structure where the value stored at children is smaller than that stored in their parents (for a min heap). It is commonly used to implement a priority queue and typically implemented with an array rather than a tree.
The following converts an array into a heap:
MinHeapify[ds : DataStructure["DynamicArray", _]] := MinHeapify[ds, 1]MinHeapify[ds_, i_] :=
Module[{l, r, p, smallest},
l = If[getLeftChildIdx[i] <= ds["Length"],
ds["Part", getLeftChildIdx[i]],
-Infinity
];
r = If[getRightChildIdx[i] <= ds["Length"],
ds["Part", getRightChildIdx[i]],
-Infinity
];
p = ds["Part", i];
smallest = If[getLeftChildIdx[i] <= ds["Length"] && l < p, getLeftChildIdx[i], i];
If[getRightChildIdx[i] <= ds["Length"] && r < ds["Part", smallest], smallest = getRightChildIdx[i]];
If[smallest =!= i,
ds["SwapPart", i, smallest];
MinHeapify[ds, smallest]
];
];getLeftChildIdx[i_] := 2igetRightChildIdx[i_] := 2i + 1getParentIdx[i_] := Quotient[i, 2]A sample data structure to use:
ds = CreateDataStructure["DynamicArray", Reverse[{9, 8, 7, 6, 5, 4, 3, 2, 1}]];This converts the array into a heap; it is hard to see the heap property:
MinHeapify[ds];
Normal[ds]This function generates a tree:
MakeHeapTree[array_] :=
Module[{data = Normal[array]},
TreeGraph[Flatten[MakeHeapTree[data, 1]], VertexLabels -> "Name", GraphLayout -> {"LayeredEmbedding", "RootVertex" -> First[data]}]
]
MakeHeapTree[arry_, idx_] := {
If[getLeftChildIdx[idx] <= Length[arry],
{
DirectedEdge[arry[[idx]], arry[[getLeftChildIdx[idx]]]],
MakeHeapTree[arry, getLeftChildIdx[idx]]
},
Nothing
],
If[getRightChildIdx[idx] <= Length[arry],
{
DirectedEdge[arry[[idx]], arry[[getRightChildIdx[idx]]]],
MakeHeapTree[arry, getRightChildIdx[idx]]
},
Nothing
]
}A visualization makes it easier to see the min heap property:
MakeHeapTree[ds]Properties & Relations (5)
InputForm (1)
InputForm returns the serialized contents of the "DynamicArray":
InputForm[CreateDataStructure["DynamicArray", Range[10]]]This serialized form can be used to recreate the data structure:
DataStructure["DynamicArray", {"Data" -> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}]Length (1)
Length can be used to get the number of elements in a "DynamicArray":
ds = CreateDataStructure["DynamicArray", Range[10]];
Length[ds]The same can be achieved with the "Length" operation:
ds["Length"]Normal (1)
Normal can be used to get the elements of a "DynamicArray":
ds = CreateDataStructure["DynamicArray", Range[10]];
Normal[ds]The same can be achieved with the "Elements" operation:
ds["Elements"]SameQ (1)
SameQ can be used to test whether two arrays contain identical elements in the same order:
ds1 = CreateDataStructure["DynamicArray", Range[10]];
ds2 = CreateDataStructure["DynamicArray", Range[10]];
ds1 === ds2If one element is dropped, the arrays are no longer the same:
ds1["DropLast"];
ds1 === ds2"FixedArray" (1)
Many algorithms that work for "DynamicArray" also work for "FixedArray".
See Also
CreateDataStructure DataStructure
Data Structures: FixedArray LinkedList ExtensibleVector DoublyLinkedList RingBuffer
Related Guides
History
Introduced in 2020 (12.1)