點燈坊

學而時習之,不亦悅乎

使用 array_entries() 同時回傳 Index 與 Element

Sam Xiao's Avatar 2019-11-28

ECMAScript 2015 迎來了 Array.prototype.entries(),可同時回傳 Array 的 Index 與 Element,但其回傳為 Array Iterator,使用上較為不便,可自行組合 array_entries() 改回傳 array,方便與其他 Ramda Function 組合。

Version

macOS Catalina 10.15.1
VS Code 1.40.2
Quokka 1.0.261
ECMAScript 2015
Ramda 0.26.1
Wink-fp 1.20.38

Array.prototype.entries()

let data = ['Sam', 'Kevin', 'Jimmy'];

let fn = arr => {
  let result = [];
  let elms = arr.entries();

  for(let x of elms) {
    let [k, v] = x;
    result.push(`${ k }: ${ v }`);
  }

  return result;
};

fn(data); // ?

由於 Array.prototype.entries() 回傳為 array iterator,因此可使用 for of loop,由於 elm 為 array,可使用 array destructuring 分解出 kv

entries000

Functional

let data = ['Sam', 'Kevin', 'Jimmy'];

let entries = arr => arr.map((v, k) => [k, v]);

let fn = arr => {
  let result = [];
  let elms = entries(arr);

  for(let x of elms) {
    let [k, v] = x;
    result.push(`${ k }: ${ v }`);
  }

  return result;
};

fn(data); // ?

由於 Array.prototype.entries() 回傳為 array iterator,只能使用 for of loop,要使用 function composition 較不方便,因此我們想自行組合 entries()

第 3 行

let entries = arr => arr.map((v, k) => [k, v]);

使用 map() 回傳 array of array,由於本質是 array,方便與其他 Ramda function 組合。

entries001

Point-free

import { map, addIndex, pipe } from 'ramda';

let data = ['Sam', 'Kevin', 'Jimmy'];

let map_ = addIndex(map);

let entries = map_((v, k) => [k, v]);

let fn = pipe(
  entries,
  map(([k, v]) => `${ k }: ${ v }`)
);

fn(data); // ?

第 5 行

let map_ = addIndex(map);

let entries = map_((v, k) => [k, v]);

也可改用 Ramda 的 addIndex()map() 組合出 map_(),再由 map_() 實現 entries()

第 9 行

let fn = pipe(
  entries,
  map(([k, v]) => `${ k }: ${ v }`)
);

既然 entries() 是 function,就很容易使用 pipe() 與其他 function 組合。

entries002

Wink-fp

import { compose, map } from 'ramda';
import { array_entries as entries } from 'wink-fp';

let data = ['Sam', 'Kevin', 'Jimmy'];

let fn = compose(
  map(([k, v]) => `${ k }: ${ v }`),
  entries
);

fn(data); // ?

Wink-fp 已經提供 entries(),可直接使用,因為 Wink-fp 同時提供 array_entries()object_entries(),故 function 名稱不一樣。

array_entries()
[a] -> [[k, v]]
回傳以 array 的 key 與 value 所構成的雙層 array

entries003

Conclusion

  • ES6 的 Array.prototype.entries() 雖有創意,但回傳 array iterator 並不好用,只能使用 for of loop 搭配 imperative 寫法
  • 透過自行組合的 entries() 回傳 array 後,就能搭配 Ramda 使用 function composition

Reference

MDN, Array.entries()
Ramda, map()
Ramda, addIndex()
Ramda, pipe()
Ramda, compose()