練習 any()

實務上我們常需判斷某一個值是否存在於 Array 內,若存在則傳回 true,若不存在則傳回 false

Version


WebStorm 2018.3.3
Quokka 1.0.134
Ramda 0.26.1

Imperative


1
2
3
4
5
6
7
8
9
10
11
12
13
const data = [1, 2, 3];

const contains = (value, data) => {
for (let item of data)
if (item === value) return true;
return false;
};

const result1 = contains(1, data);
console.log(result1);

const result2 = contains(4, data);
console.log(result2);

建立 contains(),Imperative 會使用 for loop 搭配 if 判斷,若找到資料就直接回傳 true 結束,若都找不到則回傳 false

any000

Array.prototype


1
2
3
4
5
6
7
8
9
const data = [1, 2, 3];

const contains = (fn, data) => data.some(fn);

const result1 = contains(x => x === 1, data);
console.log(result1);

const result2 = contains(x => x === 4, data);
console.log(result2);

Array.prototype 有內建 some(),可直接傳入 Arrow Function 即可。

any001

Ramda


reduce

1
2
3
4
5
6
7
8
9
10
11
import { reduce, reduced, equals } from 'ramda';

const data = [1, 2, 3];

const contains = (fn, data) => reduce((acc, val) => fn(val) && reduced(true), false, data);

const result1 = contains(equals(1), data);
console.log(result1);

const result2 = contains(equals(4), data);
console.log(result2);

若一開始並不知道 Ramda 有提供什麼 operator,最直覺的方式就是使用 reduce(),將原本 Imperative 的方式改用 reduce() 改寫。

由於只要找到值就傳回 true,因此可配合 &&,若為 true,則回傳 reduced(true) 跳出 loop,執行效率較高。

reduce()
((a, b) -> a) -> a -> [b] -> a
類似 Imperative 方式完成 loop

((a, b) -> a):其中 a 為 accumulator,而 b 為 array 的 item,回傳為 a accumulator

a: accumulator 的初始值

[b]:data 為 array

a:回傳為 accumulator

reduced()
a -> *
回傳最後一個 reduce 值,用來提早離開 loop 增進執行效率

any002

filter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { filter, length, lt, equals, pipe } from 'ramda';

const data = [1, 2, 3];

const contains = (fn, data) => pipe(
filter(fn),
length,
lt(0),
)(data);

const result1 = contains(equals(1), data);
console.log(result1);

const result2 = contains(equals(4), data);
console.log(result2);

若一開始並不知道 Ramda 有提供什麼 operator,也不想用 Imperative 與 reduce() 實作,而想採用 Compose Function 方式完成,可先挑選自己知道的 operator 下手。

filter() 為眾所皆知的 FP 代表性 operator,可藉由 length() 回傳 array 長度,若大於 0 則為 true,小於 0 則為 false,因此可搭配 lt(0),表示若 0 小於 length 則為 true,反之為 false

如此藉由 pipe() 整合 filter()length()lt() 3 個 operator,就很有 Compose Function 的味道。

filter()
(a -> boolean) -> [a] -> [a]
回傳符合條件的 array

a -> boolean: 描述 filter() 的條件,可使用 propEq()equals() 產生

[a]: data 為 array

[a]:回傳為新的 array

length()
[a] -> number
回傳 array 的長度

[a]:data 為 array

number:回傳 array 的長度

lt()
a -> a -> boolean
比較第一個參數是否小於第二個參數

a:要比較的值

a :輸入的 data

boolean:回傳比較結果

equals()
a -> b -> boolean
比較兩個值是否相等

a: 要比較的值
b:輸入的 data
boolean:回傳比較結果

any003

any

1
2
3
4
5
6
7
8
9
10
11
import { any, equals } from 'ramda';

const data = [1, 2, 3];

const contains = (fn, data) => any(fn, data);

const result1 = contains(equals(1), data);
console.log(result1);

const result2 = contains(equals(4), data);
console.log(result2);

事實上 Ramda 已經內建 any() 符合我們的需求。

any()
(a -> boolean) -> [a] -> boolean

判斷符合條件的值是否存在於 array

(a -> boolean): 判斷條件

[a]:data 為 array

boolean:回傳比較結果

any004

Conclusion


  • 只要是 for loop,理論上都可以使用 reduce() 實作,還可搭配 reduced() 提早離開 loop
  • 一開始還不熟悉 Ramda 所有 operator 時,可先使用已知的 operator 組合出需求

Reference


Ramda, any()
Ramda, reduce()
Ramda, reduced()
Ramda, filter()
Ramda, length()
Ramda, pipe()
Ramda, lt()
Ramda, equals()