來自:AnnatarHe's bloghtml
連接:https://annatarhe.github.io/2016/12/21/some-diff-filter-method.html(點擊尾部閱讀原文前往)前端
前端開發過程當中經常要對後端或管理端接口返回的數據進行處理展現,數據去重,經常用到,發現一篇好的文寫的很詳盡,記錄下來。git
測試用例以下github
import test from 'ava' import unique from '../src/unique' test('[1,1,2] should return [1, 2]', t => { t.plan(3) const src = [1,1,2] const result = unique(src) t.is(result.length, 2) t.is(result[0], 1) t.is(result[1], 2) }) test('[1, 1, "1"] should return [1, "1"]', t => { t.plan(4) const src = [1, 1, '1'] const result = unique(src) t.is(result.length, 2) t.is(result.indexOf(1), 0) t.is(typeof result[1], 'string') t.is(result.indexOf('1'), 1) }) test('deep unique', t => { const src = [1, 1, "1", false, false, true, {hello: 'world'}, [1, 2], [1, 2]] const result = unique(src) t.is(result.length, 6) }) test('deep unique', t => { const src = [1, 1, "1", false, false, true, {hello: 'world'}, [1, 2], [1, 2], {hello: 'world'}] const result = unique(src) t.is(result.length, 7) })
暫時先只看數組中存number的去重方法:後端
最粗暴的是這種,利用Set不能有重複數據的特性作數組
const unique = arr => Array.from(new Set(arr))
正常思路以下,維護一個暫存數組,將數據存進去frontend
function unique(arr) { let temp = [] for (let i = 0; i < arr.length; i++) { if (temp.indexOf(arr[i]) === -1) { temp.push(arr[i]) } } return temp }
reduce作去重(下面有參考連接),意思是每次往前一個數組中塞數據,其實就是上面正常思路的去中間變量版測試
function unique(arr) { let temp = [] for (let i = 0; i < arr.length; i++) { if (temp.indexOf(arr[i]) === -1) { temp.push(arr[i]) } } return temp }function uniqueByReduce(arr) { return arr.reduce((prev, next) => { if (prev.indexOf(next) === -1) { prev.push(next) } return prev }, []) }
這個時候基本int型數據都沒什麼問題了。spa
可是我上面測試用例中最後一個用例明顯是沒法經過的。那麼就須要更多的判斷prototype
先貼代碼:
function unique(arr) { let temp = [] for (let i = 0; i < arr.length; i++) { if (typeof arr[i] === 'object' && (! Array.isArray(arr[i]))) { if (! objects.contains(temp, arr[i])) { temp.push(arr[i]) } }else if (Array.isArray(arr[i])) { if (! arrays.contains(temp, arr[i])) { temp.push(arr[i]) } }else { if (temp.indexOf(arr[i]) === -1) { temp.push(arr[i]) } } } return temp }
意思是在推動去的時候多作一些判斷,主要是對Object和Array的斷定。
其中有objects.contains和arrays.contains兩個方法作斷定工做。其實現分別以下
// array.js
export function equals(src, dist) { if ((! Array.isArray(src)) || (! Array.isArray(dist))) { throw new Error('請傳入Array哦~??') } if (src.length !== dist.length) { return false } for (let index = 0; index < src.length; index++) { if (Array.isArray(src[index]) && Array.isArray(dist[index])) { if (! equals(src[index], dist[index])) { return false } } else { if (src[index] !== dist[index]) { return false } } } return true } export function contains(father, child) { let flags = [] father.forEach(item => { if (Array.isArray(item)) { if (equals(item, child)) { flags.push(true) } } }) return flags.indexOf(true) !== -1 }
// objects.js
function isPlainObj(obj) { return typeof obj === 'object' && (! Array.isArray(obj)) && obj !== null } export function equals(obj1, obj2) { if (Object.keys(obj1).length !== Object.keys(obj2).length) { return false } for (let item in obj1) { // 這裏簡單判斷算了,後面能夠更復雜 if (isPlainObj(obj1[item])) { if (isPlainObj(obj2[item])) { if (! equals(obj1[item], obj2[item])) { return false } }else { return false } }else { if (obj1[item] !== obj2[item]) { return false } } } return true } export function contains(father, child) { for (let key in father) { if (isPlainObj(father[key])) { // 由於只給了值,因此得有個中間層 const tempObj = { [key]: father[key] } if (equals(tempObj, child)) { return true } } } return false }
關於array.js和objects.js的測試用例我就不給出了。
反正最後測試都經過了,感受真好~
數組去重的幾個方法 http://www.zhuowenli.com/frontend/array-unique.html
Array.prototype.reduce() https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce