# Array extensions (archive)

{% tabs %}
{% tab title="JS" %}
````javascript
// 1.0.0 (2021.11.10)
// + arrayMax(), arrayMin()
// + matrixMax(), matrixMin(), matrixToString(), matrixToHTMLTable()
// + matrix(), matrixMap()
//
// 1.0.1 (2021.11.11)
// + indexOfMaxElement(arr)
//
// 1.0.2
// + indexOfMaxElement(arr), arr.indexOfMaxElement
// + array(n, opts)
//
// 1.0.3 
// - rename List -> list
// + arr.max(f), matrix.tableHTML
// - refactor: arr.indexOfMaxElement(firstN)
// - fix: matrixToHTMLTable()

import { list } from '../obj/list.js';

// --------------------- Array ---------------------

/**
 * create an array of numbers
 * ### Examples
 * ```
 * array(5) => [0,1,2,3,4]
 * array(5, {start: 1}) => [1,2,3,4,5]
 * array(3, {start: -1, step: -2}) => [-1, -3, -5]
 * ```
 * ### Parameters
 * @param {number} count - number of elements
 * @param {Object} opts - `start`: where to start, `step`: difference between two numbers.
 * @param {number} [opts.start=0] - where to start the array
 * @param {number} [opts.step=1] - the difference between two numbers
 */
export function array(count, { start = 0, step = 1 } = {}) {
  return [...list(count, { start, step })];
}

/**
 * arrayMax(arr, mapFunc)
 * ----------------------
 * - array -> max
 *
 * find the *max something* in the array.
 * the *max something* is defined by the map function `mapFunc`.
 *
 * @param {function} mapFunc - the function by which elements are mapped.
 */
export function arrayMax(arr, mapFunc = (x) => x) {
  return Math.max(...arr.map((x) => mapFunc(x)));
}

// array.max(f)
Array.prototype.max = function(f = x => x){
    return arrayMax(this, f);
};


/**
 * arrayMin(arr, mapFunc)
 * ----------------------
 * - array -> min
 *
 * find the *min something* in the array.
 * the *min something* is defined by the map function `mapFunc`.
 *
 * @param {function} mapFunc - the function by which elements are mapped.
 */
export function arrayMin(arr, mapFunc = (x) => x) {
  return Math.min(...arr.map((x) => mapFunc(x)));
}

/**
 * find index of max element, returns -1 if empty array.
 * @param {number[]} arr - array of numbers
 * @param {number} [firstN=arr.length] - search only first n elements
 */
export function indexOfMaxElement(arr, firstN=arr.length) {
    // indices = [0, 1, 2, ..., N-1]
    let indices = array(firstN);
    // find max element's index from first N elements
    return indices.reduce((iMax, i) =>
        arr[iMax] === undefined ? i : 
        arr[i] > arr[iMax]      ? i : iMax,
        -1,
    );
}

// arr.indexOfMaxElement(firstN)
Array.prototype.indexOfMaxElement = function(firstN=this.length){
    return indexOfMaxElement(this, firstN);
};


// --------------------- Matrix ---------------------

/**
 * matrixMax(matrix, mapFunc)
 * --------------------------
 * - matrix -> max
 *
 * find the *max something* in the matrix (2D array).
 * the *max something* is defined by the map function `mapFunc`.
 *
 * @param {function} mapFunc - the function by which elements are mapped.
 */
export function matrixMax(matrix, mapFunc = (x) => x) {
  return arrayMax(matrix.flat(), mapFunc);
}

/**
 * matrixMin(matrix, mapFunc)
 * --------------------------
 * - matrix -> min
 *
 * find the *min something* in the matrix (2D array).
 * the *min something* is defined by the map function `mapFunc`.
 *
 * @param {function} mapFunc - the function by which elements are mapped.
 */
export function matrixMin(matrix, mapFunc = (x) => x) {
  return arrayMin(matrix.flat(), mapFunc);
}

/**
 * matrixToString(matrix, padString)
 * ---------------------------------
 * - matrix -> string
 *
 * turn a matrix (2D array) into string.
 *
 * @param {any[][]} matrix - 2D array.
 * @param {string} padString - the string to pad with.
 */
export function matrixToString(matrix, padString = ' ') {

  // max length of elements
  const n = matrixMax(matrix, (x) => `${x}`.length);

  return matrix
    .map(
      (row) =>
        '[' +
        row.map((item) => `${item}`.padStart(n, padString)).join(' ') +
        ']',
    )
    .join('\n');
}

/**
 * matrixToHTMLTable(matrix)
 * -------------------------
 * - matrix -> `<table>` HTML string
 *
 * turn a 2D array (matrix) into HTML `<table>` tag string.
 * (intended to be used for `innerHTML` of an `HTMLElement`)
 *
 * @param {any[][]} matrix - 2D array
 */
export function matrixToHTMLTable(matrix) {
    
    // get max length of all rows (max number of columns)
    const m = matrix.max(row => row.length);
    // arr = [0, 1, 2, ..., m-1]
    const arr = array(m);

    let html = matrix.map((row) => 
            arr.map((i) => 
                `<td>${row[i] !== undefined ? row[i] : ''}</td>`
            ).join('')
        ).join(`</tr><tr>`);

    return `<table><tr>${html}</tr></table>`;
}

// ⭐️ matrix.tableHTML
Object.defineProperty(Array.prototype, 'tableHTML', {
    get: function(){
        return matrixToHTMLTable(this);
    }
});
````
{% endtab %}

{% tab title="⬇️ 應用" %}
* [bubble-sort](../../../../../appendix/algorithms/sort/bubble-sort "mention")
{% endtab %}
{% endtabs %}
