feidlambda v0.3.1

Koleksi LAMBDA feidlambda v0.3.1

Penulis

Taruma Sakti Megariansyah

Diterbitkan

Jumat, 06 Januari 2023

Diubah

Jumat, 13 Januari 2023

Official GIST feidlambda (v0.3.x)
https://gist.github.com/taruma/92bd33600a3d42dc9aead87558404a12

Panduan instalasi feidlambda v0.3.x dapat dilihat di halaman Penggunaan.

Bagi yang sebelumnya menggunakan versi feidlambda v0.2 wajib untuk membaca perubahan penting dan migrasi v0.2 ke v0.3. Tapi, bagi yang baru menggunakan bisa langsung ke bagian fungsi feidlambda v0.3.x.


Update Log v0.3.x

Update Log merupakan catatan pembaruan feidlambda. Berikut catatan perubahan/pembaruan secara umum beserta penjelasan perubahan/pembaruan. Untuk perubahan berdasarkan fungsinya, bisa dilihat di bagian Changelog.

  • Update v0.3.1 (2022-01-13)
    • Pada fungsi FILTER_MINMAX_ARRAY() terdapat argumen opsional baru yaitu take_first_only. Jika take_first_only = TRUE, maka hasil filter minimum/maksimum hanya mengambil baris pertamanya saja (jika terdapat minimum/maksimum lebih dari satu baris).
    • Pada fungsi SWAP_*(), nilai argumen from_index dan to_index menerima index negatif (indeks dari belakang). Bersamaan perubahan tersebut, nilai default to_index menjadi -1 yang artinya secara default (tanpa argumen) fungsi SWAP_*() menukar posisi terdepan dengan terbelakang (baik berdasarkan baris ataupun kolom).
    • Perubahan nama argumen pada beberapa fungsi seperti:
      • FILTER_MINMAX_COLUMN(): col -> column_index, with_lables -> with_label.
      • GET_INDEX_2D(): return_order_only -> return_as_order.
      • ROTATE_*(): n -> num_rotation.
      • TEXT_SPLIT_VECTOR(): text_delimiter -> col_delimiter.
    • Fungsi TEXT_SPLIT_VECTOR() menggunakan metode recursive dari fungsi TEXTSPLIT().
    • Pada fungsi TEXT_SPLIT_VECTOR() terdapat argumen opsional baru yaitu replace_na, yang berfungsi untuk mengubah nilai #NA dari hasil akhir.
    • Tambahan informasi limitasi pada fungsi TEXT_SPLIT_VECTOR().

Fungsi feidlambda v0.3.x

Pada feidlambda v0.3.x, setiap fungsi dikategorikan sesuai kegunaannya. Berikut kategori yang tersedia di feidlambda v0.3.x:

  • FILTER_*: Melakukan filtering atau subsetting (memilah) dari data.
  • GET_*: Mengambil informasi dari data.
  • IS_*: Fungsi logical tambahan.
  • MAKE_*: Membangkitkan data.
  • REPEAT_*: Mengulangi/merepetisi data.
  • RESHAPE_*: Mengubah dimensi data.
  • ROTATE_*: Merubah posisi data dengan diputar.
  • SWAP_*: Menukar posisi data.
  • TEXT_*: Fungsi tambahan yang berkaitan dengan teks.

Download excel demonstrasi RELEASE_feidlambda_v0_3_1.xlsx, untuk memudahkan mengeksplorasi fungsi baru di feidlambda v0.3.x.

Catatan

Gambar yang ditampilkan pada halaman ini merupakan dari versi sebelumnya (feidlambda v0.3.0) dan tidak diperbarui untuk setiap update. Oleh karena itu, disarankan untuk mengeksplorasi langsung dari dokumen yang telah dilampirkan.


Kategori FILTER_*

Kategori FILTER_* merupakan kumpulan fungsi yang melakukan filtering atau subsetting (memilah) data berupa vector ataupun array. Hubungan antar fungsi di kategori ini bisa dilihat di Gambar 3.1.

%%{ init: { 'theme': 'forest' } }%%

flowchart LR
  NONE --> FILTER_DROP_ROWS
  NONE --> FILTER_DROP_COLUMNS
  NONE --> FILTER_FUNC_COLUMN
  FILTER_FUNC_COLUMN --> FILTER_MINMAX_COLUMN
  FILTER_MINMAX_COLUMN --> _RECURSIVE_FILTER_MINMAX
  _RECURSIVE_FILTER_MINMAX --> _RECURSIVE_FILTER_MINMAX
  _RECURSIVE_FILTER_MINMAX --> FILTER_MINMAX_ARRAY

Gambar 3.1: Grafik dependencies kategori FILTER_*

Fungsi utama kategori FILTER_* yaitu FILTER_DROP_ROWS(), FILTER_DROP_COLUMNS(), dan FILTER_MINMAX_ARRAY().

Source Code FILTER_*
// NONE --> FILTER_DROP_ROWS
FILTER_DROP_ROWS = LAMBDA(array, row_index,
    LET(
        row_index, TOCOL(row_index),
        row_index_clean, FILTER(row_index, NOT(ISBLANK(row_index))),
        nrows, ROWS(array),
        row_sequence, SEQUENCE(nrows),
        selected_row, BYROW(
            row_sequence,
            LAMBDA(each_row, OR(each_row = row_index_clean))
        ),
        FILTER(array, NOT(selected_row))
    )
);

// NONE --> FILTER_DROP_COLUMNS
FILTER_DROP_COLUMNS = LAMBDA(array, column_index,
    LET(
        column_index, TOROW(column_index),
        column_index_clean, FILTER(
            column_index,
            NOT(ISBLANK(column_index))
        ),
        ncols, COLUMNS(array),
        col_sequence, SEQUENCE(1, ncols),
        selected_col, BYCOL(
            col_sequence,
            LAMBDA(each_col, OR(each_col = column_index_clean))
        ),
        FILTER(array, NOT(selected_col))
    )
);

// NONE --> FILTER_FUNC_COLUMN
FILTER_FUNC_COLUMN = LAMBDA(
    array,
    [column_index],
    [with_label],
    [label_col],
    [function],
    [label_function],
    [take_first_only],
    LET(
        take_first_only, IF(
            ISOMITTED(take_first_only),
            FALSE,
            take_first_only
        ),
        column_index, IF(ISOMITTED(column_index), 1, column_index),
        label_col, IF(ISOMITTED(label_col), column_index, label_col),
        with_label, IF(ISOMITTED(with_label), FALSE, with_label),
        function, IF(ISOMITTED(function), LAMBDA(x, MAX(x)), function),
        label_function, IF(
            ISOMITTED(label_function),
            "func",
            label_function
        ),
        selected_vector, CHOOSECOLS(array, column_index),
        func_value, function(selected_vector),
        selected_logical, selected_vector = func_value,
        array_filter, FILTER(array, selected_logical),
        array_func, IF(
            take_first_only,
            TAKE(array_filter, 1),
            array_filter
        ),
        label, MAKEARRAY(
            ROWS(array_func),
            1,
            LAMBDA(x, y, CONCAT(label_col, "_", label_function))
        ),
        IF(with_label, HSTACK(label, array_func), array_func)
    )
);

// FILTER_FUNC_COLUMN --> FILTER_MINMAX_COLUMN
FILTER_MINMAX_COLUMN = LAMBDA(
    array,
    [column_index],
    [with_label],
    [label_col],
    [take_first_only],
    LET(
        func_1, LAMBDA(x, MIN(x)),
        label_func_1, "min",
        func_2, LAMBDA(x, MAX(x)),
        label_func_2, "max",
        func1_result, FILTER_FUNC_COLUMN(
            array,
            column_index,
            with_label,
            label_col,
            func_1,
            label_func_1,
            take_first_only
        ),
        func2_result, FILTER_FUNC_COLUMN(
            array,
            column_index,
            with_label,
            label_col,
            func_2,
            label_func_2,
            take_first_only
        ),
        VSTACK(func1_result, func2_result)
    )
);

// FILTER_MINMAX_COLUMN --> _RECURSIVE_FILTER_MINMAX
// _RECURSIVE_FILTER_MINMAX --> _RECURSIVE_FILTER_MINMAX
_RECURSIVE_FILTER_MINMAX = LAMBDA(
    array,
    ntry,
    [ignore_first_column],
    [with_label],
    [label_vector],
    [take_first_only],
    LET(
        ignore_first_column, IF(
            ISOMITTED(ignore_first_column),
            FALSE,
            ignore_first_column
        ),
        stop_col, IF(ignore_first_column, 2, 1),
        label_vector, IF(
            ISOMITTED(label_vector),
            SEQUENCE(1, COLUMNS(array)),
            label_vector
        ),
        new_label, IF(
            stop_col = 2,
            HSTACK({" "}, label_vector),
            label_vector
        ),
        label_col, CHOOSECOLS(new_label, ntry),
        IF(
            ntry = stop_col,
            FILTER_MINMAX_COLUMN(
                array,
                ntry,
                with_label,
                label_col,
                take_first_only
            ),
            LET(
                results, FILTER_MINMAX_COLUMN(
                    array,
                    ntry,
                    with_label,
                    label_col,
                    take_first_only
                ),
                next_try, ntry - 1,
                VSTACK(
                    _RECURSIVE_FILTER_MINMAX(
                        array,
                        next_try,
                        ignore_first_column,
                        with_label,
                        label_vector,
                        take_first_only
                    ),
                    results
                )
            )
        )
    )
);

// _RECURSIVE_FILTER_MINMAX --> FILTER_MINMAX_ARRAY
FILTER_MINMAX_ARRAY = LAMBDA(
    array,
    [ignore_first_column],
    [with_label],
    [label_vector],
    [take_first_only],
    _RECURSIVE_FILTER_MINMAX(
        array,
        COLUMNS(array),
        ignore_first_column,
        with_label,
        label_vector,
        take_first_only
    )
);

FILTER_DROP_ROWS()

Fungsi FILTER_DROP_ROWS(array, row_index) digunakan untuk menghapus baris dari data.

Syntax
FILTER_DROP_ROWS(array, row_index)
Output
array

array := [array | vector]
Data berupa array atau vector yang memiliki baris lebih dari satu.
row_index := [integer number | integer vector]
Indeks baris yang ingin dihapus.

Gambar 3.2: Demonstrasi FILTER_DROP_ROWS()

FILTER_DROP_COLUMNS()

Fungsi FILTER_DROP_COLUMNS(array, column_index) digunakan untuk menghapus kolom dari data.

Syntax
FILTER_DROP_COLUMNS(array, column_index)
Output
array

array := [array | vector]
Data berupa array atau vector yang memiliki kolom lebih dari satu.
column_index := [integer number | integer vector]
Indeks kolom yang ingin dihapus.

Gambar 3.3: Demonstrasi FILTER_DROP_COLUMNS()

FILTER_MINMAX_ARRAY()

Fungsi FILTER_MINMAX_ARRAY(array, [ignore_first_column], [with_label], [label_vector], [take_first_only]) digunakan untuk melakukan filtering (memilah) data berdasarkan nilai minimum dan maksimum setiap kolomnya dan mengeluarkan hasil dalam berupa dynamic array.

Syntax
FILTER_MINMAX_ARRAY(array, [ignore_first_column], [with_label], [label_vector], [take_first_only])
Output
array

array := [array | numeric array]
Data berupa array dengan ketentuan array berisikan angka kecuali kolom pertama jika menggunakan opsi ignore_first_column.
[ignore_first_column] := FALSE :: [TRUE | FALSE]
Nilai default yaitu FALSE. Jika TRUE, maka kolom pertama dari array akan diabaikan dan tidak dilakukan filtering nilai minimum/maksimum.
[with_label] := FALSE :: [TRUE | FALSE]
Nilai default yaitu FALSE. Jika TRUE, maka kolom pertama dari output adalah label informasi minimum dan maksimum seperti 1_min, 1_max, atau no.column_min dan no.column_max. Untuk menggunakan label sendiri, masukin vector label di argumen label_vector.
[label_vector] := NONE :: [vector]
Nilai default yaitu NONE. Jika NONE, maka label setiap baris akan dinomori berdasarkan kolomnya (1_min, 1_max). Jika ingin menggunakan label dari nama kolom, jumlah elemen vector harus sama dengan jumlah kolom dari array. Untuk menggunakan label nilai with_label harus TRUE.
[take_first_only] := FALSE :: [TRUE | FALSE]
(New in v0.3.1). Nilai default yaitu FALSE. Jika TRUE, maka hanya baris pertama yang diambil dari hasil pencarian nilai minimum/maksimum.

Gambar 3.4: Demonstrasi FILTER_MINMAX_ARRAY()


Kategori GET_*

Kategori GET_* merupakan kumpulan fungsi yang digunakan untuk mengambil informasi dari suatu data. Hubungan antar fungsi di kategori ini bisa dilihat di Gambar 4.1.

%%{ init: { 'theme': 'forest' } }%%

flowchart LR
  NONE --> GET_INDEX_2D

Gambar 4.1: Grafik dependencies kategori GET_*

Dari Gambar 4.1, diketahui untuk versi v0.3 hanya tersedia fungsi GET_INDEX_2D().

Source Code GET_*
// NONE --> GET_INDEX_2D
GET_INDEX_2D = LAMBDA(lookup_value, array, [return_as_order],
    LET(
        return_as_order, IF(
            ISOMITTED(return_as_order),
            FALSE,
            return_as_order
        ),
        nrows, ROWS(array),
        ncols, COLUMNS(array),
        size, nrows * ncols,
        array_flatten, TOCOL(array, , TRUE),
        index_sequence, SEQUENCE(nrows, ncols, 1, 1),
        rows_sequence, MAKEARRAY(nrows, ncols, LAMBDA(x, y, x)),
        columns_sequence, MAKEARRAY(nrows, ncols, LAMBDA(x, y, y)),
        rows_flatten, TOCOL(rows_sequence, , TRUE),
        columns_flatten, TOCOL(columns_sequence, , TRUE),
        index_flatten, TOCOL(index_sequence, , TRUE),
        lookup_table, HSTACK(index_flatten, rows_flatten, columns_flatten),
        lookup_result, FILTER(lookup_table, array_flatten = lookup_value),
        IF(return_as_order, CHOOSECOLS(lookup_result, 1), lookup_result)
    )
);

// _RECURSIVE_LOOKUP --> _RECURSIVE_LOOKUP
_RECURSIVE_LOOKUP = LAMBDA(
    ntry,
    lookup_value,
    lookup_vector,
    return_array,
    [if_not_found],
    [match_mode],
    [search_mode],
    LET(
        lookup_value, TOCOL(lookup_value),
        LET(
            selected_value, VALUE(
                ARRAYTOTEXT(CHOOSEROWS(lookup_value, ntry))
            ),
            result, XLOOKUP(
                selected_value,
                lookup_vector,
                return_array,
                if_not_found,
                match_mode,
                search_mode
            ),
            IF(
                ntry = 1,
                result,
                VSTACK(
                    _RECURSIVE_LOOKUP(
                        ntry - 1,
                        lookup_value,
                        lookup_vector,
                        return_array,
                        if_not_found,
                        match_mode,
                        search_mode
                    ),
                    result
                )
            )
        )
    )
);

// _RECURSIVE_LOOKUP --> GET_XLOOKUP
GET_XLOOKUP = LAMBDA(
    lookup_value,
    lookup_vector,
    return_array,
    [if_not_found],
    [match_mode],
    [search_mode],
    LET(
        lookup_value, TOCOL(lookup_value),
        ntry, ROWS(lookup_value),
        _RECURSIVE_LOOKUP(
            ntry,
            lookup_value,
            lookup_vector,
            return_array,
            if_not_found,
            match_mode,
            search_mode
        )
    )
);

GET_INDEX_2D()

Fungsi GET_INDEX_2D(lookup_value, array, [return_as_order]) dapat digunakan untuk mengambil informasi urutan nilai yang dicari ataupun posisi baris/kolom dari array.

Syntax
GET_INDEX_2D(lookup_value, array, [return_as_order])
Output
array ([order, row index, column index]) atau number vector (order)

lookup_value := [scalar]
Nilai yang dicari dalam array. Nilai lookup_value adalah nilai tunggal berupa scalar.
array := [array]
Data berupa array.
[return_as_order] := FALSE :: [TRUE | FALSE]
Nilai default yaitu FALSE. Jika TRUE, hasil fungsi memberikan urutan angka nilai yang dicari. Urutan dimulai dari horizontal kiri teratas sampai kanan terbawah. Jika FALSE, maka output terdiri dari nomor urut, indeks kolom, dan indeks baris.

Gambar 4.2: Demonstrasi GET_INDEX_2D()


Kategori IS_*

Kategori IS_* merupakan kumpulan fungsi yang dapat digunakan untuk melakukan fungsi logical di data. Hubungan antar fungsi di kategori ini bisa dilihat di Gambar 5.1.

%%{ init: { 'theme': 'forest' } }%%

flowchart LR
  NONE --> IS_ALL_IN_LOOKUP_VECTOR
  NONE --> IS_COLS_EQUAL_LOOKUP_VECTOR
  IS_COLS_EQUAL_LOOKUP_VECTOR --> IS_ALL_COLS_EQUAL_LOOKUP_VECTOR
  NONE --> IS_ROWS_LOGICAL
  NONE --> IS_COLUMNS_LOGICAL

Gambar 5.1: Grafik dependencies kategori IS_*

Seluruh fungsi yang tersedia di kategori ini akan dijelaskan.

Source Code IS_*
// NONE --> IS_ALL_IN_LOOKUP_VECTOR
IS_ALL_IN_VECTOR = LAMBDA(lookup_vector, array,
    LET(
        lookup_vector, TOCOL(lookup_vector),
        MAP(
            array,
            LAMBDA(element,
                OR(BYROW(lookup_vector, LAMBDA(lookup, element = lookup)))
            )
        )
    )
);

// NONE --> IS_COLS_EQUAL_LOOKUP_VECTOR
IS_COLS_EQUAL_VECTOR = LAMBDA(lookup_vector, array,
    LET(
        lookup_vector, TOROW(lookup_vector),
        ncols_vector, COLUMNS(lookup_vector),
        ncols_array, COLUMNS(array),
        nrows_array, ROWS(array),
        IF(
            ncols_array = ncols_vector,
            LET(
                repeat_array, CHOOSEROWS(
                    lookup_vector,
                    SEQUENCE(nrows_array, , 1, 0)
                ),
                MAP(array, repeat_array, LAMBDA(x, y, x = y))
            ),
            "N/A"
        )
    )
);

// IS_COLS_EQUAL_LOOKUP_VECTOR --> IS_ALL_COLS_EQUAL_LOOKUP_VECTOR
IS_ALL_COLS_EQUAL_VECTOR = LAMBDA(lookup_vector, array, [logical_function],
    LET(
        logical_function, IF(
            ISOMITTED(logical_function),
            LAMBDA(x, OR(x)),
            logical_function
        ),
        array_boolean, IS_COLS_EQUAL_VECTOR(lookup_vector, array),
        BYROW(array_boolean, LAMBDA(each_row, logical_function(each_row)))
    )
);

// NONE --> IS_ROWS_LOGICAL
IS_ROWS_LOGICAL = LAMBDA(logical_array, [logical_function],
    LET(
        logical_function, IF(
            ISOMITTED(logical_function),
            LAMBDA(x, OR(x)),
            logical_function
        ),
        BYROW(logical_array, LAMBDA(each_row, logical_function(each_row)))
    )
);

// NONE --> IS_COLUMNS_LOGICAL
IS_COLUMNS_LOGICAL = LAMBDA(logical_array, [logical_function],
    LET(
        logical_function, IF(
            ISOMITTED(logical_function),
            LAMBDA(x, OR(x)),
            logical_function
        ),
        BYCOL(logical_array, LAMBDA(each_col, logical_function(each_col)))
    )
);

IS_ALL_IN_VECTOR()

Fungsi IS_ALL_IN_VECTOR(lookup_vector, array) digunakan untuk memeriksa apakah setiap elemen di array termasuk dari lookup_vector.

Syntax
IS_ALL_IN_VECTOR(lookup_vector, array)
Output
logical array

lookup_vector := [scalar | vector]
Vector yang terdiri dari nilai yang ingin dicocokkan.
array := [array | vector]
Data berupa array atau vector.

Gambar 5.2: Demonstrasi IS_ALL_IN_VECTOR()

IS_COLS_EQUAL_VECTOR()

Fungsi IS_COLS_EQUAL_VECTOR(lookup_vector, array) digunakan untuk memeriksa apakah setiap kolom di array termasuk dari setiap elemen di lookup_vector.

Syntax
IS_COLS_EQUAL_VECTOR(lookup_vector, array)
Output
logical array

lookup_vector := [vector]
Vector yang terdiri dari nilai yang ingin dicocokkan. Jumlah elemen lookup_vector harus sama dengan jumlah kolom array.
array := [array | vector]
Data berupa array .

Gambar 5.3: Demonstrasi IS_COLS_EQUAL_VECTOR()

IS_ALL_COLS_EQUAL_VECTOR()

Fungsi IS_ALL_COLS_EQUAL_VECTOR(lookup_vector, array, [logical_function]) digunakan untuk memeriksa apakah setiap kolom di array termasuk dari setiap elemen di lookup_vector, dan diperiksa apakah setiap barisnya sesuai dengan logical_function. Fungsi ini menggunakan fungsi IS_COLS_EQUAL_VECTOR().

Syntax
IS_ALL_COLS_EQUAL_VECTOR(lookup_vector, array, [logical_function])
Output
column logical vector

lookup_vector := [scalar | vector]
Vector yang terdiri dari nilai yang ingin dicocokkan. Jumlah elemen lookup_vector harus sama dengan jumlah kolom array.
array := [array | vector]
Data berupa array .
logical_function := OR() :: [LAMBDA scalar function]
Nilai default adalah fungsi lambda OR(). Fungsi logical yang digunakan untuk mengaggregasi setiap barisnya.

Gambar 5.4: Demonstrasi IS_ALL_COLS_EQUAL_VECTOR()

IS_ROWS_LOGICAL()

Fungsi IS_ROWS_LOGICAL(logical_array, [logical_function]) mengaggregasi setiap baris dari logical_array menggunakan fungsi logical_function.

Syntax
IS_ROWS_LOGICAL(logical_array, [logical_function])
Output
column vector

logical_array := [logical array]
Data berupa logical array .
[logical_function] := OR() [LAMBDA scalar function]
Nilai default adalah fungsi lambda OR(). Fungsi logical yang digunakan untuk mengaggregasi setiap barisnya.

IS_COLUMNS_LOGICAL()

Fungsi IS_COLUMNS_LOGICAL(logical_array, [logical_function]) mengaggregasi setiap kolom dari logical_array menggunakan fungsi logical_function.

Syntax
IS_COLUMNS_LOGICAL(logical_array, [logical_function])
Output
row vector

logical_array := [logical array]
Data berupa logical array .
[logical_function] := OR() [LAMBDA scalar function]
Nilai default adalah fungsi lambda OR(). Fungsi logical yang digunakan untuk mengaggregasi setiap kolomnya.

Gambar 5.5: Demonstrasi IS_ROWS_LOGICAL() dan IS_COLUMNS_LOGICAL()


Kategori MAKE_*

Kategori MAKE_* merupakan kumpulan fungsi yang membangkitkan (generate) data. Hubungan antar fungsi di kategori ini bisa dilihat di Gambar 6.1.

%%{ init: { 'theme': 'forest' } }%%

flowchart LR
  _RECURSIVE_MAKE_SEQUENCE --> _RECURSIVE_MAKE_SEQUENCE
  _RECURSIVE_MAKE_SEQUENCE --> MAKE_SEQUENCE_FROM_VECTOR

Gambar 6.1: Grafik dependencies kategori MAKE_*

Fungsi utama pada kategori ini adalah MAKE_SEQUENCE_FROM_VECTOR().

Source Code MAKE_*
// _RECURSIVE_MAKE_SEQUENCE --> _RECURSIVE_MAKE_SEQUENCE
_RECURSIVE_MAKE_SEQUENCE = LAMBDA(
    start_vector,
    end_vector,
    ntry,
    [stack_horizontally],
    LET(
        seq_start, INDEX(start_vector, ntry),
        seq_end, INDEX(end_vector, ntry),
        stack_horizontally, IF(
            ISOMITTED(stack_horizontally),
            FALSE,
            stack_horizontally
        ),
        IF(
            ntry = 1,
            SEQUENCE(seq_end - seq_start + 1, , seq_start),
            LET(
                next_try, ntry - 1,
                results, SEQUENCE(seq_end - seq_start + 1, , seq_start),
                IF(
                    stack_horizontally,
                    HSTACK(
                        _RECURSIVE_MAKE_SEQUENCE(
                            start_vector,
                            end_vector,
                            next_try,
                            stack_horizontally
                        ),
                        results
                    ),
                    VSTACK(
                        _RECURSIVE_MAKE_SEQUENCE(
                            start_vector,
                            end_vector,
                            next_try,
                            stack_horizontally
                        ),
                        results
                    )
                )
            )
        )
    )
);

// _RECURSIVE_MAKE_SEQUENCE --> MAKE_SEQUENCE_FROM_VECTOR
MAKE_SEQUENCE_FROM_VECTOR = LAMBDA(
    start_vector,
    end_vector,
    [stack_horizontally],
    _RECURSIVE_MAKE_SEQUENCE(
        start_vector,
        end_vector,
        ROWS(start_vector),
        stack_horizontally
    )
);

MAKE_SEQUENCE_FROM_VECTOR()

Fungsi MAKE_SEQUENCE_FROM_VECTOR(start_vector, end_vector, [stack_horizontally]) digunakan untuk mebangkitkan sequence dari setiap baris/elemen di start_vector dan end_vector.

Syntax
MAKE_SEQUENCE_FROM_VECTOR(start_vector, end_vector, [stack_horizontally])
Output
column vector atau array

start_vector := [integer vector]
Vector yang terdiri dari bilangan bulat memulai sequence.
end_vector := [integer vector]
Vector yang terdiri dari bilangan bulat akhir sequence.
[stack_horizontally] := FALSE :: [TRUE | FALSE]
Nilai default yaitu FALSE. Jika TRUE, maka setiap sequence yang dibangkitkan akan disusun horizontal.

Gambar 6.2: Demonstrasi MAKE_SEQUENCE_FROM_VECTOR()


Kategori REPEAT_*

Kategori REPEAT_* merupakan kumpulan fungsi yang digunakan untuk melakukan pengulangan array ataupun vector dan menghasilkannya dalam bentuk dynamic array. Hubungan antar fungsi di kategori ini bisa dilihat di Gambar 7.1.

%%{ init: { 'theme': 'forest' } }%%

flowchart LR
  REPEAT_ARRAY_BY_ROW & REPEAT_ARRAY_BY_COLUMN --> REPEAT_ARRAY
  REPEAT_ARRAY_BY_ROW --> REPEAT_ARRAY_BY_ROW
  REPEAT_ARRAY_BY_COLUMN --> REPEAT_ARRAY_BY_COLUMN

Gambar 7.1: Grafik dependencies kategori REPEAT_*

Seluruh fungsi yang tersedia di kategori ini akan dijelaskan.

Source Code REPEAT_*
// REPEAT_ARRAY_BY_ROW & REPEAT_ARRAY_BY_COLUMN --> REPEAT_ARRAY
REPEAT_ARRAY = LAMBDA(array, [num_repeat], [by_row],
    LET(
        by_row, IF(ISOMITTED(by_row), TRUE, by_row),
        num_repeat, IF(ISOMITTED(num_repeat), 2, num_repeat),
        IF(
            by_row,
            REPEAT_ARRAY_BY_ROW(array, num_repeat),
            REPEAT_ARRAY_BY_COLUMN(array, num_repeat)
        )
    )
);

// REPEAT_ARRAY_BY_ROW --> REPEAT_ARRAY_BY_ROW
REPEAT_ARRAY_BY_ROW = LAMBDA(array, [num_repeat],
    LET(
        num_repeat, IF(ISOMITTED(num_repeat), 2, num_repeat),
        IF(
            num_repeat = 1,
            array,
            LET(
                next_repeat, num_repeat - 1,
                VSTACK(REPEAT_ARRAY_BY_ROW(array, next_repeat), array)
            )
        )
    )
);

// REPEAT_ARRAY_BY_COLUMN --> REPEAT_ARRAY_BY_COLUMN
REPEAT_ARRAY_BY_COLUMN = LAMBDA(array, [num_repeat],
    LET(
        num_repeat, IF(ISOMITTED(num_repeat), 2, num_repeat),
        IF(
            num_repeat = 1,
            array,
            LET(
                next_repeat, num_repeat - 1,
                HSTACK(REPEAT_ARRAY_BY_COLUMN(array, next_repeat), array)
            )
        )
    )
);

REPEAT_ARRAY_BY_ROW()

Fungsi REPEAT_ARRAY_BY_ROW(array, [num_repeat]) digunakan untuk mengulangi array sepanjang baris (ke bawah).

Syntax
REPEAT_ARRAY_BY_ROW(array, [num_repeat])
Output
array

array := [scalar | vector | array]
Data dapat berupa scalar, vector, ataupun array.
[num_repeat] := 2 :: [integer]
Nilai default yaitu 2. Jumlah pengulangannya.

Gambar 7.2: Demonstrasi REPEAT_ARRAY_BY_ROW()

REPEAT_ARRAY_BY_COLUMN()

Fungsi REPEAT_ARRAY_BY_COLUMN(array, [num_repeat]) digunakan untuk mengulangi array sepanjang kolom (ke kanan).

Syntax
REPEAT_ARRAY_BY_COLUMN(array, [num_repeat])
Output
array

array := [scalar | vector | array]
Data dapat berupa scalar, vector, ataupun array.
[num_repeat] := 2 :: [integer]
Nilai default yaitu 2. Jumlah pengulangannya.

Gambar 7.3: Demonstrasi REPEAT_ARRAY_BY_COLUMN()

REPEAT_ARRAY()

Fungsi REPEAT_ARRAY(array, [num_repeat], [by_row]) digunakan untuk mengulangi array sepanjang baris/kolom (ke bawah/ke kanan).

Syntax
REPEAT_ARRAY(array, [num_repeat], [by_row])
Output
array

array := [scalar | vector | array]
Data dapat berupa scalar, vector, ataupun array.
[num_repeat] := 2 :: [integer]
Nilai default yaitu 2. Jumlah pengulangannya.
[by_row] := TRUE :: [TRUE | FALSE]
Nilai default yaitu TRUE. Jika TRUE, maka pengulangan akan sepanjang baris (ke bawah), dan berlaku sebaliknya juga.

Gambar 7.4: Demonstrasi REPEAT_ARRAY()


Kategori RESHAPE_*

Kategori RESHAPE_* merupakan kumpulan fungsi yang dapat digunakan untuk melakukan fungsi logical di data. Hubungan antar fungsi di kategori ini bisa dilihat di Gambar 8.1.

%%{ init: { 'theme': 'forest' } }%%

flowchart LR
  NONE --> RESHAPE_BY_COLUMNS

Gambar 8.1: Grafik dependencies kategori RESHAPE_*

Fungsi utama yang tersedia saat ini hanya RESHAPE_BY_COLUMNS().

Source Code RESHAPE_*
// NONE --> RESHAPE_BY_COLUMNS
RESHAPE_BY_COLUMNS = LAMBDA(array, [num_split],
    LET(
        num_split, IF(ISOMITTED(num_split), 2, num_split),
        ncols, COLUMNS(array),
        nrows, ROWS(array),
        IF(
            MOD(ncols, num_split) = 0,
            LET(
                divider, ncols / num_split,
                divider_sequence, CHOOSEROWS(
                    SEQUENCE(1, divider),
                    SEQUENCE(num_split, , 1, 0)
                ),
                divider_flatten, TOCOL(divider_sequence, , TRUE),
                divider_repeat, CHOOSEROWS(
                    TOROW(divider_flatten),
                    SEQUENCE(nrows, , 1, 0)
                ),
                divider_repeat_col, TOCOL(divider_repeat),
                array_flatten, TOCOL(array),
                array_sorted, SORTBY(array_flatten, divider_repeat_col),
                WRAPROWS(array_sorted, num_split)
            ),
            NA()
        )
    )
);

RESHAPE_BY_COLUMNS()

Fungsi RESHAPE_BY_COLUMNS(array, [num_split]) digunakan untuk mengubah dimensi (transformasi) array berdasarkan jumlah pembagi kolomnya. Jika tidak jumlah kolom tidak habis dibagi oleh num_split akan mengeluarkan hasil #N/A.

Syntax
RESHAPE_BY_COLUMNS(array, [num_split])
Output
array

array := [array]
Data berupa array atau vector.
[num_split] := 2 :: [integer]
Nilai default yaitu 2. Jumlah pembagi kolom. Jumlah kolom array harus habis dibagi (MOD()) dengan num_split.

Gambar 8.2: Demonstrasi RESHAPE_BY_COLUMNS()


Kategori ROTATE_*

Kategori ROTATE_* merupakan kumpulan fungsi yang digunakan untuk menggeser atau memutar array ataupun vector. Hubungan antar fungsi di kategori ini bisa dilihat di Gambar 9.1.

%%{ init: { 'theme': 'forest' } }%%

flowchart LR
  NONE --> ROTATE_VECTOR
  ROTATE_VECTOR --> ROTATE_ARRAY

Gambar 9.1: Grafik dependencies kategori ROTATE_*

Seluruh fungsi yang tersedia di kategori ini akan dijelaskan.

Source Code ROTATE_*
// NONE --> ROTATE_VECTOR
ROTATE_VECTOR = LAMBDA(vector, num_rotation, [as_column_vector],
    LET(
        vector, TOCOL(vector),
        rotated_array, IFS(
            OR(
                num_rotation = 0,
                num_rotation >= ROWS(vector),
                num_rotation <= -ROWS(vector)
            ),
            vector,
            num_rotation > 0,
            VSTACK(DROP(vector, num_rotation), TAKE(vector, num_rotation)),
            num_rotation < 0,
            VSTACK(TAKE(vector, num_rotation), DROP(vector, num_rotation))
        ),
        as_column_vector, IF(ISOMITTED(as_column_vector), FALSE, TRUE),
        IF(as_column_vector, TOROW(rotated_array), TOCOL(rotated_array))
    )
);

// ROTATE_VECTOR --> ROTATE_ARRAY
ROTATE_ARRAY = LAMBDA(array, num_rotation, [rotate_columns],
    LET(
        rotate_columns, IF(ISOMITTED(rotate_columns), TRUE, FALSE),
        nrows, ROWS(array),
        ncols, COLUMNS(array),
        seqrows, SEQUENCE(nrows),
        seqcols, SEQUENCE(1, ncols),
        results, IF(
            rotate_columns,
            CHOOSECOLS(array, ROTATE_VECTOR(seqcols, num_rotation, TRUE)),
            CHOOSEROWS(array, ROTATE_VECTOR(seqrows, num_rotation, FALSE))
        ),
        results
    )
);

ROTATE_VECTOR()

Fungsi ROTATE_VECTOR(vector, num_rotation, [as_column_vector]) digunakan untuk menggeser/memutar elemen yang ada di vector sebanyak num_rotation.

Syntax
ROTATE_VECTOR(vector, num_rotation, [as_column_vector])
Output
vector

vector := [vector]
Data berupa vector (column vector atau row vector).
num_rotation := [integer]
Jumlah berapa kali vector diputar/digeser. Nilai negatif untuk digeser berlawanan arah.
[as_column_vector] := TRUE :: [TRUE | FALSE]
Nilai default yaitu TRUE. Jika TRUE, maka output berupa column vector.

Gambar 9.2: Demonstrasi ROTATE_VECTOR()

ROTATE_ARRAY()

Fungsi ROTATE_ARRAY(array, num_rotation, [rotate_columns]) digunakan untuk menggeser/memutar elemen yang ada di array sebanyak num_rotation berdasarkan baris atau kolom.

Syntax
ROTATE_ARRAY(array, num_rotation, [rotate_columns])
Output
array

array := [array]
Data berupa array.
num_rotation := [scalar | vector]
Jumlah berapa kali vector diputar/digeser. Nilai negatif untuk digeser berlawanan arah.
[rotate_columns] := TRUE :: [TRUE | FALSE]
Nilai default yaitu TRUE. Jika TRUE, maka array diputar berdasarkan kolom. Jika FALSE, maka array diputar berdasarkan baris.

Gambar 9.3: Demonstrasi ROTATE_ARRAY()


Kategori SWAP_*

Kategori SWAP_* merupakan kumpulan fungsi yang digunakan untuk mengganti atau mengubah posisi elemen atau vector. Hubungan antar fungsi di kategori ini bisa dilihat di Gambar 10.1.

%%{ init: { 'theme': 'forest' } }%%

flowchart LR
  NONE --> SWAP_COLUMNS
  NONE --> SWAP_ROWS

Gambar 10.1: Grafik dependencies kategori SWAP_*

Seluruh fungsi yang tersedia di kategori ini akan dijelaskan.

Source Code SWAP_*
// NONE --> SWAP_COLUMNS
SWAP_COLUMNS = LAMBDA(array, [from_index], [to_index],
    LET(
        ncols, COLUMNS(array),
        from_index, IF(ISOMITTED(from_index), 1, from_index),
        to_index, IF(ISOMITTED(to_index), -1, to_index),
        from_value, IF(from_index < 0, from_index + ncols + 1, from_index),
        to_value, IF(to_index < 0, to_index + ncols + 1, to_index),
        column_sequence, SEQUENCE(1, COLUMNS(array)),
        from_logical, column_sequence = from_value,
        to_logical, column_sequence = to_value,
        replace_from, IF(from_logical, to_value, column_sequence),
        replace_to, IF(to_logical, from_value, replace_from),
        CHOOSECOLS(array, replace_to)
    )
);

// NONE --> SWAP_ROWS
SWAP_ROWS = LAMBDA(array, [from_index], [to_index],
    LET(
        nrows, ROWS(array),
        from_index, IF(ISOMITTED(from_index), 1, from_index),
        to_index, IF(ISOMITTED(to_index), -1, to_index),
        from_value, IF(from_index < 0, from_index + nrows + 1, from_index),
        to_value, IF(to_index < 0, to_index + nrows + 1, to_index),
        row_sequence, SEQUENCE(ROWS(array)),
        from_logical, row_sequence = from_value,
        to_logical, row_sequence = to_value,
        replace_from, IF(from_logical, to_value, row_sequence),
        replace_to, IF(to_logical, from_value, replace_from),
        CHOOSEROWS(array, replace_to)
    )
);

SWAP_COLUMNS()

Fungsi SWAP_COLUMNS(array, [from_index], [to_index]) digunakan untuk menukar posisi kolom ke-from_index dengan kolom ke-to_index.

Syntax
SWAP_COLUMNS(array, [from_index], [to_index])
Output
vector atau array

array := [row vector | array]
Data dapat berupa array atau row vector.
[from_index] := 1 :: [integer]
(Change in v0.3.1). Nilai default yaitu 1. Posisi index kolom yang ingin dipindahkan. Jika menggunakan indeks negatif, maka posisi diambil dari belakang.
[to_index] := -1 :: [integer]
(Change in v0.3.1). Nilai default yaitu -1. Posisi index tujuan kolom. Jika menggunakan indeks negatif, maka posisi diambil dari belakang.

SWAP_ROWS()

Fungsi SWAP_ROWS(array, [from_index], [to_index]) digunakan untuk menukar posisi baris ke-from_index dengan baris ke-to_index.

Syntax
SWAP_COLUMNS(array, [from_index], [to_index])
Output
vector atau array

array := [column vector | array]
Data dapat berupa array atau column vector.
[from_index] := 1 :: [integer]
(Change in v0.3.1). Nilai default yaitu 1. Posisi index baris yang ingin dipindahkan. Jika menggunakan indeks negatif, maka posisi diambil dari belakang.
[to_index] := -1 :: [integer]
(Change in v0.3.1). Nilai default yaitu -1. Posisi index tujuan baris. Jika menggunakan indeks negatif, maka posisi diambil dari belakang.

Gambar 10.2: Demonstrasi SWAP_COLUMNS() dan SWAP_ROWS()


Kategori TEXT_*

Kategori TEXT_* merupakan kumpulan fungsi yang digunakan untuk memproses data teks. Hubungan antar fungsi di kategori ini bisa dilihat di Gambar 11.1.

%%{ init: { 'theme': 'forest' } }%%

flowchart LR
  _RECURSIVE_TEXT_SPLIT --> _RECURSIVE_TEXT_SPLIT
  _RECURSIVE_TEXT_SPLIT --> TEXT_SPLIT_VECTOR

Gambar 11.1: Grafik dependencies kategori TEXT_*

Seluruh fungsi yang tersedia di kategori ini akan dijelaskan.

Source Code TEXT_*
// _RECURSIVE_TEXT_SPLIT --> _RECURSIVE_TEXT_SPLIT
_RECURSIVE_TEXT_SPLIT = LAMBDA(
    text_vector,
    ntry,
    col_delimiter,
    [row_delimiter],
    [ignore_empty],
    [match_mode],
    [pad_with],
    LET(
        text_vector, TOCOL(text_vector),
        selected_row, ARRAYTOTEXT(INDEX(text_vector, ntry)),
        IF(
            ntry = 1,
            TEXTSPLIT(
                selected_row,
                col_delimiter,
                row_delimiter,
                ignore_empty,
                match_mode,
                pad_with
            ),
            LET(
                next_try, ntry - 1,
                results, TEXTSPLIT(
                    selected_row,
                    col_delimiter,
                    row_delimiter,
                    ignore_empty,
                    match_mode,
                    pad_with
                ),
                VSTACK(
                    _RECURSIVE_TEXT_SPLIT(
                        text_vector,
                        next_try,
                        col_delimiter,
                        row_delimiter,
                        ignore_empty,
                        match_mode,
                        pad_with
                    ),
                    results
                )
            )
        )
    )
);

// _RECURSIVE_TEXT_SPLIT --> TEXT_SPLIT_VECTOR
TEXT_SPLIT_VECTOR = LAMBDA(
    text_vector,
    [col_delimiter],
    [row_delimiter],
    [ignore_empty],
    [match_mode],
    [pad_with],
    [replace_na],
    LET(
        nrows, ROWS(text_vector),
        col_delimiter, IF(ISOMITTED(col_delimiter), " ", col_delimiter),
        replace_na, IF(ISOMITTED(replace_na), NA(), replace_na),
        pad_with, IF(ISOMITTED(pad_with), "", pad_with),
        result, _RECURSIVE_TEXT_SPLIT(
            text_vector,
            nrows,
            col_delimiter,
            row_delimiter,
            ignore_empty,
            match_mode,
            pad_with
        ),
        IFERROR(result, replace_na)
    )
);

TEXT_SPLIT_VECTOR()

Fungsi TEXT_SPLIT_VECTOR(text_vector, [col_delimiter], [row_delimiter], [ignore_empty], [match_mode], [pad_with], [replace_na]) merupakan fungsi pengembangan lanjutan dari TEXTSPLIT() yang mampu menerima input data berupa vector dan menghasilkan dalam bentuk dynamic array.

Syntax
TEXT_SPLIT_VECTOR(text_vector, [col_delimiter], [row_delimiter], [ignore_empty], [match_mode], [pad_with], [replace_na])
Output
array

text_vector := [text vector]
Data harus berupa text column vector.
[col_delimiter] := " " :: [text]
Nilai default yaitu " " (spasi). Teks pemisah untuk setiap kolomnya.
[row_delimiter] := "" :: [text]
(Change in v0.3.1). Nilai default yaitu "" (tidak ada). Teks pemisah untuk setiap barisnya.
[ignore_empty] := FALSE :: [TRUE | FALSE]
Tentukan TRUE untuk mengabaikan pemisah berurutan. Default ke FALSE, yang membuat sel kosong. Opsional.
[match_mode] := 0 :: [0 | 1]
Tentukan 1 untuk melakukan kecocokan yang tidak peka huruf besar kecil. Default ke 0, yang melakukan kecocokan peka huruf besar kecil. Opsional.
[pad_with] := #N/A :: [text | number]
Nilai untuk mengalihkan hasil. Defaultnya adalah #N/A.
[replace_na] := #N/A :: [text | number]
(New in v0.3.1). Nilai untuk menggantikan nilai #N/A dari hasil akhir. Defaultnya adalah #N/A. Nilai #N/A yang ada dikarenakan proses VSTACK() yang memiliki dimensi hasil TEXTSPLIT() yang berbeda-beda.

Deskripsi ignore_empty, match_mode, dan pad_with diambil dari halaman Fungsi TEXTSPLIT.

Limitasi TEXT_SPLIT_VECTOR()

  • Hindari menggunakan TEXT_SPLIT_VECTOR() dengan jumlah baris yang banyak ataupun dimensi output yang besar. Pastikan hasil output fungsi memiliki dimensi yang kecil seperti jumlah kolom \(\le 10\) dan jumlah baris \(\le 1,000\).
  • Ukuran text_vector masih bisa lebih besar dari batasan diatas, akan tetapi disarankan untuk penggunaan TEXT_SPLIT_VECTOR() selalu bertahap, yaitu dari jumlah baris yang sedikit sampai jumlah baris optimal yang tidak menampilkan error atau crash.
  • Jika melebihi kemampuan, akan menghasilkan nilai error berupa #NUM / #CALC.

Gambar 11.2: Demonstrasi TEXT_SPLIT_VECTOR (outdated)


Fungsi feidlambda v0.3 memiliki \(9\) kategori dengan total \(23\) fungsi utama dan pendukung. Dengan perombakan struktur dan penamaan dari v0.2 ke v0.3, harapannya v0.3 sudah memiliki struktur dan penamaan yang konsisten sehingga untuk memproduksi fungsi ataupun fitur barunya lebih cepat di versi-versi berikutnya.

Jika ada ide untuk pengembangan feidlambda atau fungsi baru bisa langsung membuat isu di github. Dan jika bertemu masalah saat penggunaan feidlambda v0.3, bisa juga membuat isu di github.


Changelog

  • 2022-01-13 (v0.3.1)
    • Perubahan fungsi utama:
      • Perubahan FILTER_MINMAX_ARRAY():
        • Menambah optional argumen take_first_only.
        • Mengganti nama argumen: with_labels -> with_label.
        • Penyesuaian _RECURSIVE_FILTER_MINMAX() dengan posisi dan opsi argumen terbaru.
      • Perubahan GET_INDEX_2D():
        • Mengubah nama argumen: return_order_only -> return_as_order.
      • Perubahan RESHAPE_BY_COLUMNS():
        • Mengubah hasil error menjadi NA().
      • Perubahan ROTATE_VECTOR() dan ROTATE_ARRAY():
        • Mengubah nama argumen: n -> num_rotation.
      • Perubahan SWAP_COLUMNS() dan SWAP_ROWS():
        • Argumen from_index dan to_index dapat menggunakan indeks negatif.
        • Nilai default to_index menjadi -1.
      • Perubahan TEXT_SPLIT_VECTOR():
        • Mengubah metode menjadi recursive.
        • Mengubah nama argumen: text_delimiter -> col_delimiter.
        • Menambah optional argumen replace_na.
    • Perubahan fungsi pendukung:
      • Perubahan FILTER_FUNC_COLUMN():
        • Mengganti nama argumen: col -> column_index.
        • Menukar posisi argumen label_col dan with_label.
        • Menambah optional argumen take_first_only.
      • Perubahan FILTER_MINMAX_COLUMN():
        • Mengganti nama argumen: col -> column_index.
        • Menukar posisi argumen label_col dan with_label.
        • Menambah optional argumen take_first_only.
        • Penyesuaian FILTER_FUNC_COLUMN() dengan posisi dan opsi argumen terbaru.
      • Perubahan _RECURSIVE_FILTER_MINMAX():
        • Mengubah posisi argumen label_col dan with_label.
        • Penyesuaian FILTER_MINMAX_COLUMN() dengan posisi dan opsi argumen terbaru.
      • Fungsi baru _RECURSIVE_TEXT_SPLIT():
        • Fungsi pendukung TEXT_SPLIT_VECTOR().
  • 2022-01-06 (v0.3.0)
    • Rilis feidlambda v0.3