aggregate

Utilities that provide a reduced value from a collection.

(Note that this can also map the collection down first)

This can be very helpful with SourceMap.reduce() or group.by() in aggregating a series.

Types of methods:

Please note, there is nothing special for these functions, such as working with SourceMap.reduce()

They simply accept a collection and provide a result, often using the aggregate.evaluateFunctionOrProperty() with the second argument.

Overall Example

Assume we have two tyeps of values:

collection = [
  { id: 1, city: 'Seattle',  month: 'Aug', precip: 0.87 },
  { id: 0, city: 'Seattle',  month: 'Apr', precip: 2.68 },
  { id: 2, city: 'Seattle',  month: 'Dec', precip: 5.31 },
  { id: 3, city: 'New York', month: 'Apr', precip: 3.94 },
  { id: 4, city: 'New York', month: 'Aug', precip: 4.13 },
  { id: 5, city: 'New York', month: 'Dec', precip: 3.58 },
  { id: 6, city: 'Chicago',  month: 'Apr', precip: 3.62 },
  { id: 8, city: 'Chicago',  month: 'Dec', precip: 2.56 },
  { id: 7, city: 'Chicago',  month: 'Aug', precip: 3.98 }
];
// collection.map(r => r.precip);
series = [0.87, 2.68, 5.31, 3.94, 4.13, 3.58, 3.62, 2.56, 3.98];

Working with Groups

The expected way this will be used most is with the group.by(collection, field, ...) call.

(See also d3-group functionality)

utils.group.by(collection, 'city')
  .reduce((collection) => ({
    monthsReporting: utils.aggregate.unique(collection, 'month'),
    avgPrecipitation: utils.aggregate.sum(collection, 'precip'),
    numReports: utils.aggregate.length(collection),
    minPrecip: utils.aggregate.min(collection, 'precip'),
    maxPrecip: utils.aggregate.min(collection, 'precip'),
    variancePrecip: utils.aggregate.difference(collection, 'precip'),
  }))

providing
[
  {
    city: 'Seattle',
    monthsReporting: [ 'Aug', 'Apr', 'Dec' ],
    avgPrecipitation: 8.86,
    numReports: 3,
    minPrecip: 0.87,
    maxPrecip: 0.87,
    variancePrecip: 4.43999
  },
  {
    city: 'New York',
    monthsReporting: [ 'Apr', 'Aug', 'Dec' ],
    avgPrecipitation: 11.65,
    numReports: 3,
    minPrecip: 3.58,
    maxPrecip: 3.58,
    variancePrecip: 0.54999
  },
  ...
]

Using in Tables

(see TableGenerator)

new utils.TableGenerator()
    .data(
      utils.group.by(collection, 'city')
       .reduce((collection) => ({
         monthsReporting: utils.aggregate.unique(collection, 'month'),
         avgPrecipitation: utils.aggregate.sum(collection, 'precip'),
         numReports: utils.aggregate.length(collection),
         minPrecip: utils.aggregate.min(collection, 'precip'),
         maxPrecip: utils.aggregate.min(collection, 'precip'),
         variancePrecip: utils.aggregate.difference(collection, 'precip'),
       }))
    )
    .labels({ monthsReporting: 'Months',
             avgPrecipitation: 'Avg. Precip.',
             numReports: '# Reports'
    })
    .render()

Screenshot

Using in Vega Charts

(see vega module)

utils.vega.svg((vl) => vl.markLine()
   .data(
      utils.group.by(collection, 'city')
       .reduceSeparate((collection) => ({
         minPrecip: utils.aggregate.min(collection, 'precip'),
         maxPrecip: utils.aggregate.max(collection, 'precip'),
         avgPrecip: utils.aggregate.avgMean(collection, 'precip'),
       }))
   )
   .title('Precipitation by City')
   .width(400)
   .encode(
        vl.x().fieldN('city'),
        vl.y().fieldQ('_aggregateValue').title('Precipitation'),
        vl.color().fieldN('_aggregateKey').title('Calculation')
   )
);

Screenshot

Working with Simple Arrays

Simple arrays do not need a mapping function or property, we can simply pass null (or no second argument at all).

series = [0.87, 2.68, 5.31, 3.94, 4.13, 3.58, 3.62, 2.56, 3.98];
utils.aggregate.min(series, null);
// provides 0.87

This is the same as series.sort(utils.array.SORT_ASCENDING)[0]

Working with Mapping Functions

If we want a specific value, we can pass a mapping function first.

collection = [
  { id: 1, city: 'Seattle',  month: 'Aug', precip: 0.87 },
  { id: 0, city: 'Seattle',  month: 'Apr', precip: 2.68 },
  ...
];

utils.aggregate.min(collection, (r) => r.precip);
// provides 0.87

This is the same as:

collection.map(r => r precip)
   .sort(utils.array.SORT_ASCENDING)[0]

Working with Object Properties

If we have a specific property (or key) in our 2d collection, then we can just pass that instead.

collection = [
  { id: 1, city: 'Seattle',  month: 'Aug', precip: 0.87 },
  { id: 0, city: 'Seattle',  month: 'Apr', precip: 2.68 },
  ...
];

utils.aggregate.min(collection, 'precip');
// provides 0.87

This is the same as:

collection.map(r => r precip)
   .sort(utils.array.SORT_ASCENDING)[0]

Methods

(static) avgMean(collection, accessor) → {Number}

Finds the mean value (sum of all values / # of values)

Example
utils.aggregate.avgMean([0.87, 2.68, 5.31, 3.94, 4.13, 3.58, 3.62, 2.56]);
// 3.41
Parameters:
Name Type Description
collection Array
accessor function | String

function to identify the property, string property name or null

Returns:
  • mean average
Type
Number

(static) avgMedian(collection, accessor) → {Number}

Finds the median (halfway number in a sorted series)

Example
utils.aggregate.avgMedian([0.87, 2.68, 5.31, 3.94, 4.13, 3.58, 3.62, 2.56]);
// [0.87,2.56,2.68,3.58,3.62,3.94,3.98,4.13,5.31]
//                      3.62
Parameters:
Name Type Description
collection Array
accessor function | String

function to identify the property, string property name or null

Returns:
  • median number from the series
Type
Number

(static) coalesce(collection, evaluationFnopt) → {Object}

See:

Coalesces a collection of objects to return a single object that has the first non-null value of all unique properties found in the collection.

example:

collection = [
 { first: 'john' },
 { last: 'doe' },
 { age: 23 }
];
utils.agg.coalesce(collection);
// { first: 'john', last: 'doe', age: 23 };

this also works to show example values for a large number of objects

collection = [
  { first: 'john', last: 'doe', age: 23, failedClass: null },
  { first: 'jane', last: 'doe', favouriteColor: 'blue', failedClass: null },
  null,
  { first: 'bill', favouriteColor: 'red', failedClass: 'asbx-dx2' }
];
utils.agg.coalesce(collection);
//-- now we can understand the types of values we got for each property type
// { first: 'john', last: 'doe', age: 23, favouriteColor: 'blue', failedClass: 'asbx-dx2' }

Note - an optional evaluationFn can be provided, that can be used to determine if a value is collected.

collection = [{ val: null }, { val: 23 }, { val: 2 }, { val: 100 }];
maxCoalesce = (val, current) => val && (!current || val > current);
utils.agg.coalesce(collection, maxCoalesce);
// { val: 100 }
Parameters:
Name Type Attributes Description
collection Array
evaluationFn function <optional>

optional function that defines the value collected

  • function(entryValue:any, currentCoalescedValue:any, entryPropName:string, entry:Object):Boolean
Returns:
  • Object with all properties found, and the first
Type
Object

(static) count(collection, accessor, uniquifierFnopt) → {Object}

See:
  • .countMap - for a map of results that are not converted to string

Identifies how frequently something has occurred as a value.

Note that this also includes a function to make the value unique, so Objects can be compared, because checking equality of Objects is only true if the operands reference the same Object.)

See module:aggregate.unique for more

Example
const source = [
  { city: 'Chicago' }, { city: 'Seattle' }, { city: 'New York' },
  { city: 'Chicago' }, { city: 'Seattle' }, { city: 'AmsterDam' }
];
utils.aggregate.count(source, 'city');
// { Chicago: 2, Seattle: 2, 'New York': 1, Amsterdam: 1 };
utils.aggregate.count(source, 'city').Chicago
// 2

series = [
  { station: 'A', timestamp: new Date(2022, 0, 1, 9) },
  { station: 'B', timestamp: new Date(2022, 0, 1, 9, 30) },
  { station: 'A', timestamp: new Date(2022, 0, 1, 10, 0) },
  { station: 'B', timestamp: new Date(2022, 0, 2, 9) },
  { station: 'A', timestamp: new Date(2022, 0, 2, 9, 30) },
  { station: 'B', timestamp: new Date(2022, 0, 2, 10, 0) },
  { station: 'A', timestamp: new Date(2022, 0, 3, 10, 0) },
  { station: 'B', timestamp: new Date(2022, 0, 3, 10, 0 }
]
utils.aggregate.count(series, 'timestamp', (d) => d.toISOString().slice(0, 10))
// { '2022-01-01': 3, '2022-01-02': 2, '2022-01-03': 2 }
Parameters:
Name Type Attributes Description
collection Array
accessor function | String

function to identify the property, string property name or null

uniquifierFn function <optional>

optional function to make values unique

Returns:
  • with unique values as props, and counts as values
Type
Object

(static) countMap(collection, accessor, uniquifierFnopt) → {Map}

See:
  • .count - for an object that convert to string easier

Identifies how frequently something has occurred as a value.

Note that this also includes a function to make the value unique, so Objects can be compared, because checking equality of Objects is only true if the operands reference the same Object.)

See module:aggregate.count for more

Example
const source = [
  { city: 'Chicago' }, { city: 'Seattle' }, { city: 'New York' },
  { city: 'Chicago' }, { city: 'Seattle' }, { city: 'AmsterDam' }
];
utils.aggregate.count(source, 'city');
// Map([['Chicago', 2], ['Seattle', 2], ['New York', 1], ['Amsterdam'], 1])
utils.aggregate.countMap(source, 'city').get('Chicago')
// 2
Parameters:
Name Type Attributes Description
collection Array
accessor function | String

function to identify the property, string property name or null

uniquifierFn function <optional>

optional function to make values unique

Returns:
  • unique values -> count of how often it was identified
Type
Map

(static) deferCollection(aggregateFn, …restopt) → {function}

Converts an aggregate function to two functions - one that takes all arguments except the collection and one that takes only the collection.

For example:

utils.aggregate.unique(collection, (r) => r.city))
//-- all unique city values in the collection
// ['Chicago', 'New York', 'Seattle', 'Amsterdam']

but what if we know we want the city properties, but don't have the collection yet?

const uniqueCity = utils.aggregate.deferCollection(utils.aggregate.unique, (r) => r.city);
...
uniqueCity(collection)
//-- all the unique city values in the collection
// ['Chicago', 'New York', 'Seattle', 'Amsterdam']

note that this is also available under an alias defer

const uniqueCity = utils.agg.defer(utils.agg.unique, 'city');
...
uniqueCity(collection)
//-- all the unique city values in the collection
// ['Chicago', 'New York', 'Seattle', 'Amsterdam']
Parameters:
Name Type Attributes Description
aggregateFn function
rest any <optional>
<repeatable>

any arguments past the collection argument

Returns:
  • (collection) => aggregateFn.apply(this, [collection, ...rest])
Type
function

(static) difference(collection, accessor) → {Number}

The difference between the lowest and the highest values in the collection

Example
utils.aggregate.difference([0.87, 2.68, 5.31, 3.94, 4.13, 3.58, 3.62, 2.56]);
// 4.44  (max: 5.31 - min: 0.87 = 4.4)
Parameters:
Name Type Description
collection Array
accessor *
Returns:
Type
Number

(static) distinct(collection, accessor, uniquifierFnopt) → {Number}

Counts the unique values.

Note that this includes an additional bucketing function - useful for objects. (As String('A') !== String('A)' - because

because checking equality of Objects is only true if the operands reference the same Object.)

See module:aggregate.count for more

Example
utils.aggregate.unique(['apple', 'orange', 'apple', 'banana']);
// 3 - e.g [ 'apple', 'orange', 'banana' ].length
Parameters:
Name Type Attributes Description
collection Array
accessor function | String

function to identify the property, string property name or null

uniquifierFn function <optional>

optional function to make values unique

Returns:
  • unique values
Type
Number

(static) duplicates(collection, accessor, uniquifierFnopt) → {Array}

See:

Determines the values that were duplicated

Note that this also includes a function to make the value unique, so even Dates, Objects, etc can be compared, because checking equality of Objects is only true if the operands reference the same Object.)

See module:aggregate.count for more

Example
const source = [
  { city: 'Chicago' }, { city: 'Seattle' }, { city: 'New York' },
  { city: 'Chicago' }, { city: 'Seattle' }, { city: 'AmsterDam' }
];
utils.aggregate.duplicates(source, 'city');
// ['Chicago', 'Seattle']
Parameters:
Name Type Attributes Description
collection Array
accessor function | String

function to identify the property, string property name or null

uniquifierFn function <optional>

optional function to make values unique

Returns:
  • array of the duplicate values
Type
Array

(static) extent(collection, accessor) → {Object}

Identifies the min and max of values of a collection

Example
utils.aggregate.extent([0.87, 2.68, 5.31, 3.94, 4.13, 3.58, 3.62, 2.56]);
// { min: 0.87, max: 5.31 }
Parameters:
Name Type Description
collection Array
accessor function | String

function to identify the property, string property name or null

Returns:
  • structure of ({ min, max })
Type
Object

(static) first(collection, accessor) → {any}

Finds the first value in a list.

NOTE: this short circuits and can be helpful if the values are all identical

Example
utils.aggregate.first([null, undefined, 0.87, 2.68, 5.31, 3.94, 4.13, 3.58, 3.62, 2.56]);
// 0.87
Parameters:
Name Type Description
collection Array
accessor function | String

function to identify the property, string property name or null

Returns:
  • the first non undefined || null value found
Type
any

(static) isUnique(collection, accessor) → {Boolean}

Determines whether the values in the collection are unique.

Example
let data = [{ val: 1 }, { val: 2 }, { val: 3 }, { val: 1 }];
aggregate.isUnique(data, 'val'); // false

let data = [{ val: 1 }, { val: 2 }, { val: 3 }];
aggregate.isUnique(data, 'val'); // true

data = ['a', 'b', 'c', 'd'];
aggregate.isUnique(data); // true
Parameters:
Name Type Description
collection Array
accessor function | String

function to access the value, string property or null

Returns:
  • whether the values in the array are truly unique
Type
Boolean

(static) length(collection) → {Number}

Number of records found in the collection

Example
utils.aggregate.count([0.87, 2.68, 5.31, 3.94, 4.13, 3.58, 3.62, 2.56]);
// 8
Parameters:
Name Type Description
collection Array
Returns:
Type
Number

(static) max(collection, accessor) → {any}

Identifies the largest value in a collection of values.

(Note that this works with anything comparable with > )

Example
utils.aggregate.max([0.87, 2.68, 5.31, 3.94, 4.13, 3.58, 3.62, 2.56]);
// 5.31
Parameters:
Name Type Description
collection Array
accessor function | String

function to identify the property, string property name or null

Returns:
  • largest value where result > any other value in collection
Type
any

(static) min(collection, accessor) → {any}

Identifies the smallest value in a collection of values.

(Note that this works with anything comparable with <)

Example
utils.aggregate.min([0.87, 2.68, 5.31, 3.94, 4.13, 3.58, 3.62, 2.56]);
// 0.87
Parameters:
Name Type Description
collection Array
accessor function | String

function to identify the property, string property name or null

Returns:
  • smallest value where result < any other value in collection
Type
any

(static) notIn(collection, accessor, possibleSuperSet) → {Set}

Determines the values in collection that are not in he possibleSuperSet.

This can be helpful in validating a superSet does indeed include all the values.

Example
const superSet = new Set(['a', 'b', 'c']);
const data = [{ val: 'a' }, { val: 'b' }, { val: 'c' }, { val: 'd' }];

aggregate.notIn(data, 'val', superSet);
// Set('d')
Parameters:
Name Type Description
collection Array
accessor function | String

function to identify the value or string property name or null if array of values

possibleSuperSet Iteratable

Array or Set that we want to identify which values are not in

Returns:
  • set of values from collection not in the possibleSuperSet
Type
Set

(static) percentile(collection, accessor, pct) → {Number}

Returns a given percentile from a list of objects.

Note: this simply aggregates the values and passes to the Percentile NPM Package

Example
const data = [{ record: 'jobA', val: 1 }, { record: 'jobA', val: 2 },
 { record: 'jobA', val: 3 }, { record: 'jobA', val: 4 },
 { record: 'jobA', val: 5 }, { record: 'jobA', val: 6 },
 { record: 'jobA', val: 7 }, { record: 'jobA', val: 8 },
 { record: 'jobA', val: 9 }, { record: 'jobA', val: 10 }
];

utils.aggregate.percentile(data, 'val', 50) //-- returns 5
utils.aggregate.percentile(data, (r) => r.val, 70) //-- returns 7
Parameters:
Name Type Description
collection Array.<Object>

collection of objects

accessor function | String

function to access the value, string property or null

pct Number

Percentile (either .5 or 50)

Returns:
  • the pct percentile of a property within the collection
Type
Number

(static) percentile_01(collection, accessor) → {Number}

See:
  • percentile - as this simply hard codes the percentage

Returns a hard coded percentage

See Percentage for more detail

Parameters:
Name Type Description
collection Array.<Object>

collection of objects

accessor function | String

function to access the value, string property or null

Returns:
  • the percentile of a property within the collection
Type
Number

(static) percentile_05(collection, accessor) → {Number}

See:
  • percentile - as this simply hard codes the percentage

Returns a hard coded percentage

See Percentage for more detail

Parameters:
Name Type Description
collection Array.<Object>

collection of objects

accessor function | String

function to access the value, string property or null

Returns:
  • the percentile of a property within the collection
Type
Number

(static) percentile_10(collection, accessor) → {Number}

See:
  • percentile - as this simply hard codes the percentage

Returns a hard coded percentage

See Percentage for more detail

Parameters:
Name Type Description
collection Array.<Object>

collection of objects

accessor function | String

function to access the value, string property or null

Returns:
  • the percentile of a property within the collection
Type
Number

(static) percentile_25(collection, accessor) → {Number}

See:
  • percentile - as this simply hard codes the percentage

Returns a hard coded percentage

See Percentage for more detail

Parameters:
Name Type Description
collection Array.<Object>

collection of objects

accessor function | String

function to access the value, string property or null

Returns:
  • the percentile of a property within the collection
Type
Number

(static) percentile_50(collection, accessor) → {Number}

See:
  • percentile - as this simply hard codes the percentage

Returns a hard coded percentage

See Percentage for more detail

Parameters:
Name Type Description
collection Array.<Object>

collection of objects

accessor function | String

function to access the value, string property or null

Returns:
  • the percentile of a property within the collection
Type
Number

(static) percentile_75(collection, accessor) → {Number}

See:
  • percentile - as this simply hard codes the percentage

Returns a hard coded percentage

See Percentage for more detail

Parameters:
Name Type Description
collection Array.<Object>

collection of objects

accessor function | String

function to access the value, string property or null

Returns:
  • the percentile of a property within the collection
Type
Number

(static) percentile_90(collection, accessor) → {Number}

See:
  • percentile - as this simply hard codes the percentage

Returns a hard coded percentage

See Percentage for more detail

Parameters:
Name Type Description
collection Array.<Object>

collection of objects

accessor function | String

function to access the value, string property or null

Returns:
  • the percentile of a property within the collection
Type
Number

(static) percentile_95(collection, accessor) → {Number}

See:
  • percentile - as this simply hard codes the percentage

Returns a hard coded percentage

See Percentage for more detail

Parameters:
Name Type Description
collection Array.<Object>

collection of objects

accessor function | String

function to access the value, string property or null

Returns:
  • the percentile of a property within the collection
Type
Number

(static) percentile_99(collection, accessor) → {Number}

See:
  • percentile - as this simply hard codes the percentage

Returns a hard coded percentage

See Percentage for more detail

Parameters:
Name Type Description
collection Array.<Object>

collection of objects

accessor function | String

function to access the value, string property or null

Returns:
  • the percentile of a property within the collection
Type
Number

(static) property(objectArray, propertyOrFn) → {Array}

Maps an array of values to a single property.

For example:

const data = [{ record: 'jobA', val: 1 }, { record: 'jobA', val: 2 },
 { record: 'jobA', val: 3 }, { record: 'jobA', val: 4 },
 { record: 'jobA', val: 5 }, { record: 'jobA', val: 6 },
 { record: 'jobA', val: 7 }, { record: 'jobA', val: 8 },
 { record: 'jobA', val: 9 }, { record: 'jobA', val: 10 }
];

utils.object.propertyFromList(data, 'val')
//-- [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

utils.object.propertyFromList(data, (r) => r.val);
//-- [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
Parameters:
Name Type Description
objectArray Array.<Object>

Array of Objects to be mapped to a single property / value

propertyOrFn function | String

Name of the property or Function to return a value

Returns:
  • Array of values
Type
Array

(static) sum(collection, accessor) → {any}

Sum of the values.

Example
utils.aggregate.sum([0.87, 2.68, 5.31, 3.94, 4.13, 3.58, 3.62, 2.56]);
// 26.69
Parameters:
Name Type Description
collection Array
accessor function | String

function to identify the property, string property name or null

Returns:
  • largest value where result > any other value in collection
Type
any

(static) topValues(collection, numValuesopt, fieldOrFnopt, …sortFields) → {Array}

Returns the Top N values from within a collection.

For example, if we have a list of weather records, we can get the month with the greatest rain.

Note: this can also return the Bottom N values, if sorting in ascending order. (see array.createSort() for more.)

collection = [
  { id: 0, month: '2021-Sep', precip: 2.68 },
  { id: 1, month: '2021-Aug', precip: 0.87 },
  { id: 2, month: '2021-Oct', precip: 5.31 },
  { id: 3, month: '2021-Nov', precip: 3.94 },
  { id: 4, month: '2021-Dec', precip: 4.13 },
  { id: 5, month: '2022-Jan', precip: 3.58 },
  { id: 6, month: '2022-Feb', precip: 3.62 },
  { id: 7, month: '2022-Mar', precip: 3.98 },
  { id: 8, month: '2022-Apr', precip: 2.56 }
];

//-- We can get the top 3 months with the highest rainfall
utils.aggregate.topValues(collection, 3, 'month', '-precip');
// '2021-Oct', '2021-Dec', '2022-Mar'

//-- Or the 3 most recent precipitation values:
utils.aggregate.topValues(collection, 3, 'precip', '-id');
// 2.56, 3.98, 3.62

//-- Lowest Rainfall is simply sorting in ascending order
utils.aggregate.topValues(collection, 5, 'month', 'precip');
// 0.87, 2.56, 2.68, 3.58, 3.62

//-- you can also combine values to make the values clearer, by passing a function
const monthPrecip = function (record) => `${record.month} (${record.precip})`;
utils.aggregate.topValues(collection, 3, monthPrecip, '-precip');
// '2021-Oct (5.31)', '2021-Dec (4.13)', '2022-Mar (3.98)'

Literal values are also supported

collection = [ 2.68, 0.87, 5.31, 3.94, 4.13, 3.58, 3.62, 3.98, 2.56 ];

//-- top 5 values
utils.aggregate.topValues(collection, 5);
utils.aggregate.topValues(collection, 5, null, '-')
// [5.31, 4.13, 3.98, 3.94, 3.62]

//-- bottom 5 values
utils.aggregate.topValues(collection, 5, null, '');
// 
Parameters:
Name Type Attributes Default Description
collection Array

Collection of values we want to get the top values from

numValues Number <optional>
5

the number of values to return

fieldOrFn string | function <optional>
null

field of the object to use as the value,
Or the Function to generate the value,
Or null if the value is an array of Comparables (like Number)

sortFields String <repeatable>

field in the object to sort by,
Prefixed by '-' if it should be sorted in Descending order (ex: '-Year', 'Manufacturer')

Returns:
  • array of values
Type
Array

(static) unique(collection, accessor, uniquifierFnopt) → {Array}

Identifies the unique values from the collection.

Note that this includes an additional bucketing function - useful for objects. (As String('A') !== String('A)' - because because checking equality of Objects is only true if the operands reference the same Object.)

See module:aggregate.count for more

Example
utils.aggregate.unique(['apple', 'orange', 'apple', 'banana']);
// [ 'apple', 'orange', 'banana' ]
Parameters:
Name Type Attributes Description
collection Array
accessor function | String

function to identify the property, string property name or null

uniquifierFn function <optional>

optional function to make values unique

Returns:
  • unique values
Type
Array