摘要:實(shí)現(xiàn)數(shù)組更多的高階函數(shù)吾輩的博客原文場(chǎng)景雖說(shuō)人人平等,但有些人更加平等。若是有一篇適合萌新閱讀的自己實(shí)現(xiàn)數(shù)組更多操作的文章,情況或許會(huì)發(fā)生一些變化。類似于的初始值,但它是一個(gè)函數(shù),避免初始值在所有分組中進(jìn)行累加。
JavaScript 實(shí)現(xiàn)數(shù)組更多的高階函數(shù)
吾輩的博客原文: https://blog.rxliuli.com/p/fc...場(chǎng)景
雖說(shuō)人人平等,但有些人更加平等。
為什么有了 Lodash 這種通用函數(shù)工具庫(kù),吾輩要寫(xiě)這篇文章呢?吾輩在 SegmentFault 上經(jīng)常看到關(guān)于 JavaScript 數(shù)組的相關(guān)疑問(wèn),甚至于,相同類型的問(wèn)題,只是數(shù)據(jù)變化了一些,就直接提出了一個(gè)新的問(wèn)題(實(shí)際上,對(duì)自身并無(wú)幫助)。簡(jiǎn)單搜索了一下 Array,居然有 2360+ 條的結(jié)果,足可見(jiàn)這類問(wèn)題的頻率之高。若是有一篇適合 JavaScript 萌新閱讀的自己實(shí)現(xiàn)數(shù)組更多操作的文章,情況或許會(huì)發(fā)生一些變化。
下面吾輩便來(lái)實(shí)現(xiàn)以下幾種常見(jiàn)的操作
uniqueBy: 去重
sortBy: 排序
filterItems: 過(guò)濾掉一些元素
diffBy: 差異
groupBy: 分組
arrayToMap: Array 轉(zhuǎn)換為 Map
遞歸操作
前言:uniqueBy: 去重
你至少需要了解 ES6 的一些特性你才能愉快的閱讀
相關(guān)問(wèn)題
javascript 怎么實(shí)現(xiàn)多種數(shù)據(jù)類型的數(shù)組去重?
JS 有沒(méi)有比較高效的數(shù)組去重的方法?
/** * js 的數(shù)組去重方法 * @param arr 要進(jìn)行去重的數(shù)組 * @param kFn 唯一標(biāo)識(shí)元素的方法,默認(rèn)使用 {@link returnItself} * @returns 進(jìn)行去重操作之后得到的新的數(shù)組 (原數(shù)組并未改變) */ function uniqueBy(arr, kFn = val => val) { const set = new Set() return arr.filter((v, ...args) => { const k = kFn(v, ...args) if (set.has(k)) { return false } set.add(k) return true }) }
使用
console.log(uniqueBy([1, 2, 3, "1", "2"])) // [ 1, 2, 3, "1", "2" ] console.log(uniqueBy([1, 2, 3, "1", "2"], i => i + "")) // [ 1, 2, 3 ]sortBy: 排序
相關(guān)問(wèn)題
js 中如何對(duì)含有特殊字符的數(shù)組進(jìn)行排序?
以下數(shù)組怎么按名稱排序
/** * 快速根據(jù)指定函數(shù)對(duì)數(shù)組進(jìn)行排序 * 注: 使用遞歸實(shí)現(xiàn),對(duì)于超大數(shù)組(其實(shí)前端的數(shù)組不可能特別大吧?#笑)可能造成堆棧溢出 * @param arr 需要排序的數(shù)組 * @param kFn 對(duì)數(shù)組中每個(gè)元素都產(chǎn)生可比較的值的函數(shù),默認(rèn)返回自身進(jìn)行比較 * @returns 排序后的新數(shù)組 */ function sortBy(arr, kFn = v => v) { // TODO 此處為了讓 typedoc 能生成文檔而不得不加上類型 const newArr = arr.map((v, i) => [v, i]) function _sort(arr, fn) { // 邊界條件,如果傳入數(shù)組的值 if (arr.length <= 1) { return arr } // 根據(jù)中間值對(duì)數(shù)組分治為兩個(gè)數(shù)組 const medianIndex = Math.floor(arr.length / 2) const medianValue = arr[medianIndex] const left = [] const right = [] for (let i = 0, len = arr.length; i < len; i++) { if (i === medianIndex) { continue } const v = arr[i] if (fn(v, medianValue) <= 0) { left.push(v) } else { right.push(v) } } return _sort(left, fn) .concat([medianValue]) .concat(_sort(right, fn)) } return _sort(newArr, ([t1, i1], [t2, i2]) => { const k1 = kFn(t1, i1, arr) const k2 = kFn(t2, i2, arr) if (k1 === k2) { return 0 } else if (k1 < k2) { return -1 } else { return 1 } }).map(([_v, i]) => arr[i]) }
使用
console.log(sortBy([1, 3, 5, 2, 4])) // [ 1, 2, 3, 4, 5 ] console.log(sortBy([1, 3, 5, "2", "4"])) // [ 1, "2", 3, "4", 5 ] console.log(sortBy([1, 3, 5, "2", "4"], i => -i)) // [ 5, "4", 3, "2", 1 ]filterItems: 過(guò)濾掉一些元素
相關(guān)問(wèn)題
過(guò)濾數(shù)組子集
對(duì)比兩組對(duì)象數(shù)組 根據(jù)元素內(nèi)某一屬性是否相等過(guò)濾數(shù)組
/** * 從數(shù)組中移除指定的元素 * 注: 時(shí)間復(fù)雜度為 1~3On * @param arr 需要被過(guò)濾的數(shù)組 * @param deleteItems 要過(guò)濾的元素?cái)?shù)組 * @param kFn 每個(gè)元素的唯一鍵函數(shù) */ function filterItems(arr, deleteItems, kFn = v => v) { const kSet = new Set(deleteItems.map(kFn)) return arr.filter((v, i, arr) => !kSet.has(kFn(v, i, arr))) }
使用
console.log(filterItems([1, 2, 3, 4, 5], [1, 2, 0])) // [ 3, 4, 5 ] console.log(filterItems([1, 2, 3, 4, 5], ["1", "2"], i => i + "")) // [ 3, 4, 5 ]diffBy: 差異
相關(guān)問(wèn)題
JS 求兩個(gè)對(duì)象數(shù)組的差集
JavaScript 數(shù)組系列問(wèn)題:數(shù)組差集
/** * 比較兩個(gè)數(shù)組的差異 * @param left 第一個(gè)數(shù)組 * @param right 第二個(gè)數(shù)組 * @param kFn 每個(gè)元素的唯一標(biāo)識(shí)產(chǎn)生函數(shù) * @returns 比較的差異結(jié)果 */ function diffBy(left, right, kFn = v => v) { // 首先得到兩個(gè) kSet 集合用于過(guò)濾 const kThanSet = new Set(left.map(kFn)) const kThatSet = new Set(right.map(kFn)) const leftUnique = left.filter((v, ...args) => !kThatSet.has(kFn(v, ...args))) const rightUnique = right.filter( (v, ...args) => !kThanSet.has(kFn(v, ...args)), ) const kLeftSet = new Set(leftUnique.map(kFn)) const common = left.filter((v, ...args) => !kLeftSet.has(kFn(v, ...args))) return { left: leftUnique, right: rightUnique, common } }
使用
console.log(diffBy([1, 2, 3], [2, 3, 4])) // { left: [ 1 ], right: [ 4 ], common: [ 2, 3 ] } console.log(diffBy([1, 2, 3], ["2", 3, 4])) // { left: [ 1, 2 ], right: [ "2", 4 ], common: [ 3 ] } console.log(diffBy([1, 2, 3], ["2", 3, 4], i => i + "")) // { left: [ 1 ], right: [ 4 ], common: [ 2, 3 ] }groupBy: 分組
相關(guān)問(wèn)題
求一個(gè)數(shù)組按屬性分組的方法
js 數(shù)組分組?
/** * js 數(shù)組按照某個(gè)條件進(jìn)行分組 * * @param arr 要進(jìn)行分組的數(shù)組 * @param kFn 元素分組的唯一標(biāo)識(shí)函數(shù) * @param vFn 元素分組的值處理的函數(shù)。第一個(gè)參數(shù)是累計(jì)值,第二個(gè)參數(shù)是當(dāng)前正在迭代的元素,如果你使用過(guò) {@link Array#reduce} 函數(shù)的話應(yīng)該對(duì)此很熟悉 * @param init 每個(gè)分組的產(chǎn)生初始值的函數(shù)。類似于 reduce 的初始值,但它是一個(gè)函數(shù),避免初始值在所有分組中進(jìn)行累加。 * @returns 元素標(biāo)識(shí) => 數(shù)組映射 Map */ function groupBy( arr, kFn = v => v, /** * 默認(rèn)的值處理函數(shù) * @param res 最終 V 集合 * @param item 當(dāng)前迭代的元素 * @returns 將當(dāng)前元素合并后的最終 V 集合 */ vFn = (res, item) => { res.push(item) return res }, init = () => [], ) { // 將元素按照分組條件進(jìn)行分組得到一個(gè) 條件 -> 數(shù)組 的對(duì)象 return arr.reduce((res, item, index, arr) => { const k = kFn(item, index, arr) // 如果已經(jīng)有這個(gè)鍵了就直接追加, 否則先將之初始化再追加元素 if (!res.has(k)) { res.set(k, init()) } res.set(k, vFn(res.get(k), item, index, arr)) return res }, new Map()) }
使用
console.log(groupBy([1, 2, 2, 2, 4, 4, 5, 5, 6], i => i)) // Map { 1 => [ 1 ],? 2 => [ 2, 2, 2 ],? 4 => [ 4, 4 ],? 5 => [ 5, 5 ],? 6 => [ 6 ] } console.log(groupBy([1, 2, 2, 2, 4, 4, 5, 5, 6], i => i % 2 === 0)) // Map { false => [ 1, 5, 5 ], true => [ 2, 2, 2, 4, 4, 6 ] } console.log( groupBy( [1, 2, 2, 2, 4, 4, 5, 5, 6], i => i % 2 === 0, (res, i) => res.add(i), () => new Set(), ), ) // Map { false => Set { 1, 5 }, true => Set { 2, 4, 6 } }arrayToMap: 轉(zhuǎn)換為 Map
相關(guān)問(wèn)題
js 怎么把數(shù)組下面的對(duì)象里面的兩個(gè)字段取出來(lái)組成一個(gè)新的對(duì)象,key:value 形式
/** * 將數(shù)組映射為 Map * @param arr 數(shù)組 * @param k 產(chǎn)生 Map 元素唯一標(biāo)識(shí)的函數(shù),或者對(duì)象元素中的一個(gè)屬性名 * @param v 產(chǎn)生 Map 值的函數(shù),默認(rèn)為返回?cái)?shù)組的元素,或者對(duì)象元素中的一個(gè)屬性名 * @returns 映射產(chǎn)生的 map 集合 */ export function arrayToMap(arr, k, v = val => val) { const kFn = k instanceof Function ? k : item => Reflect.get(item, k) const vFn = v instanceof Function ? v : item => Reflect.get(item, v) return arr.reduce( (res, item, index, arr) => res.set(kFn(item, index, arr), vFn(item, index, arr)), new Map(), ) }
使用
const county_list = [ { id: 1, code: "110101", name: "東城區(qū)", citycode: "110100", }, { id: 2, code: "110102", name: "西城區(qū)", citycode: "110100", }, { id: 3, code: "110103", name: "崇文區(qū)", citycode: "110100", }, ] console.log(arrayToMap(county_list, "code", "name")) // Map { "110101" => "東城區(qū)", "110102" => "西城區(qū)", "110103" => "崇文區(qū)" } console.log(arrayToMap(county_list, ({ code }) => code, ({ name }) => name)) // Map { "110101" => "東城區(qū)", "110102" => "西城區(qū)", "110103" => "崇文區(qū)" }遞歸
相關(guān)問(wèn)題
復(fù)雜數(shù)組去重
JavaScript 數(shù)組中包含數(shù)組如何去重?
以上種種操作皆是對(duì)一層數(shù)組進(jìn)行操作,如果我們想對(duì)嵌套數(shù)組進(jìn)行操作呢?例如上面這兩個(gè)問(wèn)題?其實(shí)問(wèn)題是類似的,只是遞歸遍歷數(shù)組而已。
/** * js 的數(shù)組遞歸去重方法 * @param arr 要進(jìn)行去重的數(shù)組 * @param kFn 唯一標(biāo)識(shí)元素的方法,默認(rèn)使用 {@link returnItself},只對(duì)非數(shù)組元素生效 * @returns 進(jìn)行去重操作之后得到的新的數(shù)組 (原數(shù)組并未改變) */ function deepUniqueBy(arr, kFn = val => val) { const set = new Set() return arr.reduce((res, v, i, arr) => { if (Array.isArray(v)) { res.push(deepUniqueBy(v)) return res } const k = kFn(v, i, arr) if (!set.has(k)) { set.add(k) res.push(v) } return res }, []) }
使用
const testArr = [ 1, 1, 3, "hello", [3, 4, 4, "hello", "5", [5, 5, ["a", "r"]]], { key: "test", }, 4, [3, 0, 2, 3], ] console.log(deepUniqueBy(testArr)) // [ 1,? 3,? "hello",? [ 3, 4, "hello", "5", [ 5, [Object] ] ],? { key: "test" },? 4,? [ 3, 0, 2 ] ]反例
事實(shí)上,目前 SegmentFault 上存在著大量低質(zhì)量且重復(fù)的問(wèn)題及回答,關(guān)于這點(diǎn)確實(shí)比不上 StackOverflow。下面是兩個(gè)例子,可以看一下能否發(fā)現(xiàn)什么問(wèn)題
js 怎么把數(shù)組下面的對(duì)象里面的兩個(gè)字段取出來(lái)組成一個(gè)新的對(duì)象,key:value 形式
JS 中處理 JSON 數(shù)據(jù)重復(fù)問(wèn)題,取出里面 name 字段數(shù)值相同的作為一個(gè)數(shù)組;不相同的作為一個(gè)數(shù)組?
事實(shí)上,不管是問(wèn)題還是答案,都沒(méi)有突出核心 -- Array 映射為 Map/Array 分組,而且這種問(wèn)題和答案還層出不窮。如果對(duì) Array 的 API 都沒(méi)有看過(guò)一遍就來(lái)詢問(wèn)的話,對(duì)于幫助者來(lái)說(shuō)卻是太失禮了!
總結(jié)JavaScript 對(duì)函數(shù)式編程支持很好,所以習(xí)慣高階函數(shù)于我們而言是一件好事,將問(wèn)題的本質(zhì)抽離出來(lái),而不是每次都局限于某個(gè)具體的問(wèn)題上。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/105360.html
摘要:高階函數(shù)如果一個(gè)函數(shù)操作其他函數(shù),即將其他函數(shù)作為參數(shù)或?qū)⒑瘮?shù)作為返回值,那么我們可以將其稱為高階函數(shù)。我們可以使用高階函數(shù)對(duì)一系列操作和值進(jìn)行抽象。高階函數(shù)有多種表現(xiàn)形式。腳本數(shù)據(jù)集數(shù)據(jù)處理是高階函數(shù)表現(xiàn)突出的一個(gè)領(lǐng)域。 來(lái)源:ApacheCN『JavaScript 編程精解 中文第三版』翻譯項(xiàng)目原文:Higher-Order Functions 譯者:飛龍 協(xié)議:CC BY-NC-...
摘要:歡迎您的支持系列目錄復(fù)習(xí)資料資料整理個(gè)人整理重溫基礎(chǔ)篇重溫基礎(chǔ)對(duì)象介紹重溫基礎(chǔ)對(duì)象介紹重溫基礎(chǔ)介紹重溫基礎(chǔ)相等性判斷重溫基礎(chǔ)閉包重溫基礎(chǔ)事件本章節(jié)復(fù)習(xí)的是中的高階函數(shù),可以提高我們的開(kāi)發(fā)效率。 本文是 重溫基礎(chǔ) 系列文章的第二十一篇。 今日感受:想家。 本人自己整理的【Cute-JavaScript】資料,包含:【ES6/ES7/ES8/ES9】,【JavaScript基礎(chǔ)...
摘要:前言函數(shù)式編程在前端已經(jīng)成為了一個(gè)非常熱門(mén)的話題。整個(gè)過(guò)程就是體現(xiàn)了函數(shù)式編程的核心思想通過(guò)函數(shù)對(duì)數(shù)據(jù)進(jìn)行轉(zhuǎn)換。高階函數(shù)函數(shù)式編程傾向于復(fù)用一組通用的函數(shù)功能來(lái)處理數(shù)據(jù),它通過(guò)使用高階函數(shù)來(lái)實(shí)現(xiàn)。 前言 函數(shù)式編程在前端已經(jīng)成為了一個(gè)非常熱門(mén)的話題。在最近幾年里,我們看到非常多的應(yīng)用程序代碼庫(kù)里大量使用著函數(shù)式編程思想。 本文將略去那些晦澀難懂的概念介紹,重點(diǎn)展示在 JavaScrip...
摘要:前言在學(xué)習(xí)前端的時(shí)候,我總是能聽(tīng)到很多高級(jí)詞匯,比如今天會(huì)聊到的函數(shù)式編程高階函數(shù)。接下來(lái)我們看看,高階函數(shù)有可能會(huì)遇到的問(wèn)題,又如何去解決。 前言 在學(xué)習(xí)前端的時(shí)候,我總是能聽(tīng)到很多高級(jí)詞匯,比如今天會(huì)聊到的 函數(shù)式編程(Functional Programming) & 高階函數(shù) (Higher-order function) 。但是當(dāng)你真正的理解什么是 函數(shù)式編程 & 高階函數(shù) ...
閱讀 3898·2021-11-22 13:54
閱讀 2673·2021-09-30 09:48
閱讀 2359·2021-09-28 09:36
閱讀 3110·2021-09-22 15:26
閱讀 1342·2019-08-30 15:55
閱讀 2509·2019-08-30 15:54
閱讀 1424·2019-08-30 14:17
閱讀 2340·2019-08-28 18:25