/** * * 根據秒數返回 一個日期範圍 * timerFilter(10) */ function timerFilter(n) { let days = 31; // 一月多少天 const oneM = 60; // 一分鐘s const halfAnHour = oneM * 30; // 半小時s const oneHour = oneM * 60 * 1; // 一小時s const oneDay = oneHour * 24; // 一天s const oneMonth = oneDay * days; // 一個月s const oneYearAllDay = 365; const oneYearAllS = oneYearAllDay * oneDay; if (n < oneM) { return `${n}秒前`; } else if (n >= oneM && n < halfAnHour) { return `${Math.floor(n / oneM)}分鐘前`; } else if (n >= halfAnHour && n < oneHour) { return `半小時前`; } else if (n >= oneHour && n < oneDay) { return `${Math.floor(n / oneHour)}小時前`; } else if (n >= oneDay && n < oneMonth) { return `${Math.floor(n / oneDay)}天前`; } else if (n >= oneMonth && n < oneYearAllS) { return `${Math.floor(n / oneMonth)}月前`; } else if (n >= oneYearAllS) { return `${Math.floor(n / oneYearAllS)}年前`; } } /** * * x年 12個月,每個月有幾天 * month12Day(): [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] */ function month12Day(year) { if (!year) { const date = new Date(); year = date.getFullYear(); } const months = []; for (let i = 0; i < 12; i++) { const index = i + 1; let date2 = new Date(year, index, 0); let days = date2.getDate(); months.push(days); } return months; } /** * * x年x月 有多少天,默認本年本月 * monthAllDay('2019', 2) // 28 */ function monthAllDay(year, month) { if (!year || !month) { const date = new Date(); year = date.getFullYear(); month = date.getMonth() + 1; } const date2 = new Date(year, month, 0); const days = date2.getDate(); // 本月有多少天 return days; } /** * 判斷全部角的終邊是否相等 * @param {*} angles * finalSide([30, 390, 750]) -> true */ function finalSide(angles) { angles = angles.map(angle => { if (angle > 360) { return angle - Math.floor(angle / 360) * 360; } else { return angle; } }); return !angles.some(angle => angle !== angles[0]); } /** * 判斷一個角的終邊處於在第幾象限角 * @param {*} angle 角度 * quadrant(-180) */ function quadrant(angle) { // 是否爲負的角 const quadrantNum = 4; // 只有4個象限 const quadrantItem = 90; // 每一個象限爲90度 let isNegative = false; if (angle < 0) { isNegative = true; angle = Math.abs(angle); } // 不屬於任何現象角 if (angle % quadrantItem === 0) return null; const x = Math.ceil(angle / quadrantItem); return isNegative ? quadrantNum - x + 1 : x; } /** * 楊輝三角 * @param {*} lines 行數 * https://zh.wikipedia.org/wiki/%E6%9D%A8%E8%BE%89%E4%B8%89%E8%A7%92%E5%BD%A2 * https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/pascal-triangle * ShowYangHuiTriangle(10); */ function ShowYangHuiTriangle(lines) { let str = ``; let nums = []; for (let i = 0; i < lines; i++) { //補空白 for (let j = 0; j < lines - i; j++) { str += " "; } for (let j = 0; j < i + 1; j++) { let length = nums.length; let value; if (j === 0 || j === i) { value = 1; // 左右爲1 } else { value = nums[length - i] + nums[length - i - 1]; } nums.push(value); str += ` ${value} `; } str += "\r\n"; } l(str); } // 檢查一個正整數是否爲 2 的冪 // https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/is-power-of-two function is2Power(number) { return (number & (number - 1)) === 0 ? true : false; } // 階乘 // 5! = 5 * 4 * 3 * 2 * 1 = 120 // https://github.com/trekhleb/javascript-algorithms/blob/master/src/algorithms/math/factorial/README.zh-CN.md function factorial(number) { let r = 1, i; for (i = number; i > 0; i--) { r *= i; } return r; } // 最小公倍數 // lcm(a, b) = |a * b| / gcd(a, b) // https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/least-common-multiple function lcm(numbers = []) { numbers = numbers.map(n => Math.abs(n)); return numbers.reduce((acc, el) => el * acc, 1) / gcd(numbers); } // 求公約數 // https://baike.baidu.com/item/%E6%9C%80%E5%A4%A7%E5%85%AC%E7%BA%A6%E6%95%B0 // https://en.wikipedia.org/w/index.php?title=Euclidean_algorithm&gettingStartedReturn=true // https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/euclidean-algorithm function gcd(numbers) { const [resNumbers, n] = a(numbers); const x = b(resNumbers); // 第一步中約掉的若干個2與第二步中等數的乘積就是所求的最大公約數 if (n === 0) { return x; } else { return x * 2 ** n; } /** * * @param {*} numbers * @param {*} n 整除了幾回 */ function a(numbers, n = 0) { const len = numbers.length; let isAllEven = true; // 是否都是偶數 let i = 0; for (i = 0; i < len; i++) { if (numbers[i] % 2 !== 0) { isAllEven = false; break; } } if (isAllEven) { // 都是偶數, 則用2約簡 const newNumbers = numbers.map(n => n / 2); return a(newNumbers, n + 1); } else { return [numbers, n]; } } function b(numbers) { // 以較大的數減較小的數,接着把所得的差與較小的數比較,並以大數減少數。繼續這個操做,直到所得的減數和差相等爲止。 const maxNumber = Math.max(...numbers); const minNumber = Math.min(...numbers); const x = maxNumber - minNumber; // l(x); if (x === minNumber) { return x; } else { return b([minNumber, x]); } } } // flattenDeep(arr, 2) https://www.css88.com/doc/lodash/#_flattendeptharray-depth1 function flattenDeep(arr, depath = -2, res = []) { for (let el of arr) { const isArr = el.constructor === Array; if ((isArr && depath >= 1) || (depath === -2 && isArr)) { flattenDeep(el, Math.max(depath - 1, -2), res); } else { res.push(el); } } return res; } // Docs: http://www.css88.com/doc/lodash/#_throttlefunc-wait0-options function throttle(fn, rate = 1000) { let lastClick = Date.now() - rate; return function(...args) { if (Date.now() - lastClick >= rate) { fn(...args); lastClick = Date.now(); } }; } // 將數字從一個範圍從新映射到另外一個範圍 // Docs: https://p5js.org/reference/#/p5/map // Docs: https://github.com/processing/p5.js/blob/master/src/math/calculation.js function our_map(v, start1, stop1, start2, stop2) { return (v - start1) / (stop1 - start1) * (stop2 - start2) + start2; } // 和下面的chunk 同樣 function chunk2(arr, n) { let len = arr.length; return new Array(Math.ceil(len / n)) .fill() .reduce((acc, el, index, target) => { var start = index * n, end = Math.min(start + n, len); acc.push([]) for (let i = start; i < end; i++) { acc[index].push(arr[i]); } return acc; }, []) } // chunk([1, 2, 3], 2) -> [[1, 2], [3]] function chunk(arr, n) { let res = []; arr = arr.slice() let len = arr.length; let from = Math.ceil(len / n) for (let i = 0; i < from; i++) { let a = [] for (let j = 0; j < n; j++) { let v = arr.shift(); if (v !== undefined) a.push(v); } res.push(a) } return res; } // 'click-value-x-Z' -> camelHD -> clickValueXZ function camelHD(str) { let a = str.split(/-/) let len = a.length; for (let i = 1; i < len; i++) { let c = a[i].codePointAt(0); if (c >= 65 && c <= 90) continue; // A ~ Z let obj = a[i] a[i] = obj.replace(/^[a-z]{0,1}/, obj[0].toUpperCase()) } return a.join('') } // 打亂集合裏面的元素位置 function shuffle(arr) { const random = (a, b) => Math.floor(Math.random() * (b - a + 1) + a); return arr.slice().reduce((acc, item, index, target) => { const objIndex = random(0, index); target.splice(index, 1, target[objIndex]); target.splice(objIndex, 1, item); return target; }); } // 返回 start - end數字之間的素數。 function getPrime(start, end) { const res = []; for (let i = start; i <= end; i++) { if (primenp(i)) res.push(i); } return res; } // 判斷一個數字是否爲 素數 // 指在大於1的天然數中,除了1和該數自身外,沒法被其餘天然數整除的數 // https://zh.wikipedia.org/wiki/%E7%B4%A0%E6%95%B0 function primenp(n) { if (n <= 1) return false; for (let i = 2; i < n; i++) { if (n % i === 0) return false; } return true; } function random(a, b) { // 0 * n = 0; +a是爲了保證最小值 return Math.floor((Math.random() * (b - a + 1)) + a); } // 默認返回32位隨機字符串 function randomString32(len) { const loopn = len || 32; const c = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'; const c_len = c.length; let res = ''; for (let i = 0; i < loopn; i++) { res += c.charAt(random(0, c_len - 1)); } return res; } // node 返回MD5加密後的字符串 function MD5(data) { const md5 = crypto.createHash('md5', 'utf8').update(data).digest('hex'); return md5; } // { name: 'ajanuw', age: [12, 14] } -> jsonToSerialize -> name=ajanuw&age=12&age=14 function jsonToSerialize(o) { let s = ''; for (let k in o) { let v = o[k]; let vTag = Object.prototype.toString.call(v); if (vTag === '[object Array]') { for (let i of v) { s += `${k}=${encodeURIComponent(i)}&` } } else if (vTag === '[object Object]') { s += `${k}=${encodeURIComponent(JSON.stringify(v))}&` } else { s += `${k}=${encodeURIComponent(v)}&` } } return s.replace(/&$/, ''); } function charCode(string) { // char-code 返回與字符相關的數字 return string.codePointAt(0); } function codeChar(number) { // code-char 返回與數字相關的字符 return String.fromCodePoint(number); } function bubbleSort(arr, is = '<') { // 網上找的排序,帶破壞性 var len = arr.length; for (var i = 0; i < len; i++) { for (var j = 0; j < len - 1 - i; j++) { if (is === '<') { if (arr[j] > arr[j + 1]) { //相鄰元素兩兩對比 var temp = arr[j + 1]; //元素交換 arr[j + 1] = arr[j]; arr[j] = temp; } } else { if (arr[j] < arr[j + 1]) { //相鄰元素兩兩對比 var temp = arr[j + 1]; //元素交換 arr[j + 1] = arr[j]; arr[j] = temp; } } } } return arr; } // 指出相等元素出現的次數 // occ(['a', 'b', 'a', 'd', 'a', 'c', 'd', 'c', 'a']) // [["a", 4],["d", 2],["c", 2],["b", 1]] function occ(lst) { let res = []; let n = 0; // 數組去重 let lsta = (function (array) { let n = []; for (let i = 0; i < array.length; i++) { if (n.indexOf(array[i]) === -1) n.push(array[i]); } return n; })(lst); for (let i = 0; i < lsta.length; i++) { const key = lsta[i]; for (let j = 0; j < lst.length; j++) { if (lst[j] === key) { n += 1; } } res.push([key, n]); n = 0; } return res.sort((a, b) => { return a[1] < b[1] }); } // 若是其中一個參數爲真,當即返回當前元素, some直接返回true // or(false,1,false) // 1 function or() { const props = ([]).slice.call(arguments); for (let el of props) { if (el || el === 0) { // js會把0轉化成false return el }; } return false; } function and() { const props = ([]).slice.call(arguments); for (let el of props) { if (!el && el !== 0) return false; } return props.pop(); } function ourSplit(dataStr, splitData, addStr) { /** * 這個函數更 split很想,可是有三個參數 * 在分割的時候同時 在前或在後 添加第三個參數 * * console.log( ourSplit('1-2--34-5--6--', '--', '?hello') ); * console.log( ourSplit('1-2-----3', '-', '?xx') ); */ if (splitData.constructor !== String) { // 分割失敗返回 false return false; } if (!addStr) { // 不存在第三個參數,就更split同樣 return dataStr.split(splitData); } if (addStr.constructor !== String) { // 分割失敗返回 false return false; } const dataStrLength = dataStr.length; //分割字符串的長度 const isGetPlaceholder = addStr.charAt(0) === '?'; const a1 = []; // splitData 存在的座標 if (isGetPlaceholder) { for (let i = 0; i < dataStrLength; i++) { if (dataStr.substr(i, splitData.length) === splitData) { a1.push(i); } } const addStrData = addStr.slice(1); // 須要添加的數據 const res = []; // 分割後的 數據 let start = 0; for (let i = 0; i < a1.length + 1; i++) { res.push( i < a1.length ? dataStr.substring(start, a1[i]) + addStrData : dataStr.substring(start, a1[i]) ); start = a1[i] + splitData.length } return res; } } // 這個函數用來用多個函數來處理 一個參數 // function mu(n) { return n ** 2 } // apllyfunc(3, [mu, [Number.prototype.toFixed, 2]]) // 9.00 function apllyfunc(target, f = []) { if (f.constructor !== Array) { throw Error(`${f.name}:應該是'Array', 而不是'${f.constructor.name}'`); } if (f.length === 0) { return target; } let res = target; const checkFunction = fn => fn.constructor === Function ? '' : console.error(`${fn}:不是'Function'.`); let fn; f.reduce((accumulator, el) => { if (el.constructor === Array) { fn = el[0]; checkFunction(fn); return res = fn.call(res, el[1]) } else { fn = el; checkFunction(fn); return res = fn(res); } }, res); return res; } // 迴文有偶數個元素,那麼後半段會是前半段的鏡射 // mirror([1,2,2,1]) function mirror(lst) { const len = lst.length; if (len % 2 !== 0) return false; let mid = len / 2; const a = lst.slice(0, mid); const b = lst.slice(mid).reverse(); let res = true; while (res && mid > 0) { res = a[mid - 1] == b[mid - 1]; mid--; } return res; } function complement(s, a) { /* * 補集 (complement) 遞歸版 * S是一個集合,A是S的一個子集,由S中全部不屬於A的元素組成的集合,叫作子集A在S中的絕對補集 * console.log( * complement([1, 2, 3, 1, 2], [2, 3]) * ); */ if (s.constructor !== Array && a.constructor !== Array) return false; if (s.length === 0) return []; const obj = s[0]; const check = a.indexOf(obj) < 0; // S中全部不屬於A的元素 return check ? [obj, ...complement(s.slice(1), a)] : [...complement(s.slice(1), a)] } function complement(s, a) { /* * 補集 (complement) * S是一個集合,A是S的一個子集, * 由S中全部不屬於A的元素組成的集合,叫作子集A在S中的絕對補集 * console.log(complement([1, 2, 3, 1, 2], [2, 3])); * [1, 1] */ if (s.constructor === Array && a.constructor === Array) { const com = s.filter(el => a.indexOf(el) < 0); // S中全部不屬於A的元素 return com.length > 0 ? com : false; } return false; } function intersection(lstA, lstB) { /* * 交集 (intersection) 遞歸版 * A,B是兩個集合,由全部屬於集合A且屬於集合B的元素所組成的集合 * console.log( * intersection([1,2,3,4,2], [2,3,5]) * ); */ if (lstA.constructor !== Array && lstB.constructor !== Array) return false; if (lstA.length === 0) return []; const value = lstA[0]; const check = lstB.indexOf(value) >= 0; // 相交 return check ? [lstA[0], ...intersection(lstA.slice(1), lstB)] : [...intersection(lstA.slice(1), lstB)] } function intersection(lstA, lstB) { /* * 交集 (intersection) * A,B是兩個集合,由全部屬於集合A且屬於集合B的元素所組成的集合 * console.log(intersection([1, 2, 3, 4, 2], [2, 3, 5])); * [2, 3, 2] */ return (lstA.constructor === Array && lstB.constructor === Array) ? lstA.filter(el => lstB.indexOf(el) >= 0) : false; } function union(lstA, lstB) { /* * 並集 (union) * 若A和B是集合,則A和B並集是有全部A的元素和全部B的元素,而沒有其餘元素的集合。 * console.log(union([1, 2], [2, 3])); * [1, 2, 3] */ return (lstA.constructor === Array && lstB.constructor === Array) ? ([...lstA, ...lstB]).reduce((acc, el) => [...acc, acc.indexOf(el) < 0 ? el : ''], []).filter(el => el !== '') : false; } // 遍歷樹, 更改修改值 // arr = [1, 2, "y", ['y', 'a', ['z','z','y']]] // subtr('p', 'y', arr) function subtr(newV, oldV, tree) { if (oldV === tree) { return newV; } if ((tree).constructor !== Array || tree.length === 0) { return tree; } return [ subtr(newV, oldV, tree[0]), ...subtr(newV, oldV, tree.slice(1)), ]; } // 拷貝數組 // copyTree([1,2, ['a', 'b'], 6, 9, {}]) function copyTree(tr) { if (tr.constructor !== Array || tr.length === 0) { return tr; } return [ copyTree(tr[0]), ...copyTree(tr.slice(1)) ] } // mapList([1, 2, 3, "a", "b"], lst => lst.slice(2)) // [ [ 1, 2, 3, 'a', 'b' ], [ 'a', 'b' ] ] function mapList(lst, next) { if (lst.length === 0 || lst.constructor !== Array) return; let arr = []; let a = list => { if (list.length === 0 || list.constructor !== Array) return []; arr.push(list); return a(next(list.slice(1))); }; a(lst.slice()); return arr; } // ourSort([1,2,3,6,-1], '<') function ourSort(lst, n) { let newlst = lst.slice(); if (n && n === '>') { // 從大到小 return newlst.sort((a, b) => a < b); } else if (n && n === '<') { // 從小到大 return newlst.sort((a, b) => a > b); } } function AVector(x = 0, y = 0, z = 0) { // 模擬 p5.js 的 p5.p5.Vector 對象 this.x = x; this.y = y; this.z = z; this.test = 'ajanuw'; this.add = function (v) { // 相加 if (v) { this.x += v.x; this.y += v.y; this.z += v.z; } } this.sub = function (v) { // 相減 if (v) { this.x -= v.x; this.y -= v.y; this.z -= v.z; } } this.mult = function (n) { // 乘以標量以延伸向量 if (n) { this.x *= n; this.y *= n; } } this.div = function (n) { // 除以標量以縮短向量 if (n) { this.x /= n; this.y /= n; } } this.mag = function () { // 計算向量長度,勾股定理 return Math.sqrt(this.x * this.x + this.y * this.y) } this.setMag = function (v) { // 設置向量的長度 } this.normalize = function () { // 單位化向量,使其長度爲1 var m = this.mag(); if (m !== 0) { this.div(m); } } this.limit = function (max) { // 限制向量的長度 } this.constructor = function () { return { x: this.x, y: this.y, z: this.z, } } this.constructor(); } function fangen(target, n) { /** * 求方根 * Math.pow(2,3) * 2**3 */ // fangen(10, 2) // 100 if (n == 0) { return target; } function abc(intertarget, n) { if (n == 0) { return intertarget; } return abc(intertarget * target, n - 1) } return abc(target, n - 1) } function average(a = []) { // 求平均值 // average([1, 2, 3]) // 2 var i = 0, len = a.length, all = 0; while (i < len) { all += a[i]; i++ } return all / len; } function variance(a = []) { // 求方差和 // 方差 = 每一個元素減去平均值的平方根 ( a[i] - average(a) )^2 // 方差和 = (+ fangen( a[i] - average(a), 2)) var len = a.length, all = 0, avg = average(a); for (let i = 0; i < len; i++) { all += fangen(a[i] - avg, 2); } return all; } function gaussian(a = []) { // 求標準差 // 標準差 = 方差和,在平均後,在方根 // Math.sqrt( variance(a) / a.len) // gaussian([85, 82, 88, 86, 85, 93, 98, 40, 73, 83]) // 15.126466871017833 return Math.sqrt(variance(a) / a.length); } // 控制檯打印顏色 [yarn add chalk] // console.log( logger("hello", {string: 'red'}) ); // console.log( logger(123, 'red') ); function logger(target, obj = {}) { var inspect = util.inspect; if (typeof obj === 'object') { Object.assign(inspect.styles, obj); } else { Object.assign(inspect.styles, { [typeof target]: obj }); } return inspect(target, { colors: true }).replace(/'/g, ''); } // _slice('a..t') // _slice('b..z') function _slice(str) { if (str.constructor.name !== 'String') return !!0; var start, end, cStart, cEnd, arr = []; start = str.charAt(0); end = str.charAt(str.length - 1); if (start < end) { cStart = start.codePointAt(0); cEnd = end.codePointAt(0); for (let i = cStart; i <= cEnd; i++) { arr.push(String.fromCodePoint(i)); } } else { cEnd = start.codePointAt(0); cStart = end.codePointAt(0); for (let i = cEnd; i >= cStart; i--) { arr.push(String.fromCodePoint(i)); } } return arr; } //返回對象的prop [] function keys(obj, isOwn = false) { var a = []; if (isOwn) { return Reflect.ownKeys(obj); } else { for (let i in obj) a.push(i); } return a; } //返回對象的value[] function values(obj, isOwn = false) { var a = []; if (isOwn) { let i, al = Reflect.ownKeys(obj); for (i in al) a.push(obj[al[i]]); } else { for (let i in obj) a.push(obj[i]); } return a; } function _date(s) { // _date('w') 星期二 var odate; if (s.constructor === Array) { // 返回指定時間 if (s.length === 1) { return new Date(s[0]).getTime(); // 返回時間搓 } else { odate = new Date(s[0]) return nowT(s[1]); // 返回指定參數 } } odate = new Date() return nowT(s); function nowT(ti) { // 返回當前時間 switch (ti) { case 'y': return odate.getFullYear(); // 年 break; case 'm': return odate.getMonth() + 1; // 月 break; case 'd': return odate.getDate(); // 日 break; case 'h': return odate.getHours(); // 小時 break; case 'n': return odate.getMinutes(); // 分鐘 break; case 's': return odate.getSeconds(); // 秒 break; case 'w': return odate.getDay(); // 星期 break; case 'ms': return odate.getMilliseconds(); // 毫秒 break; case 'prc': return odate.toLocaleString() // 本地時間格式 break; default: return Date.now(); // 時間搓 } } } // 遞歸建立文件夾 // [在那個文件夾下建立, 建立新文件夾的list, 回調函數] function _mkdirs(dir, lst, next) { if (lst.length === 0) { next(null, dir); return true; } var d = path.join(dir, lst[0]) fs.mkdir(d, err => { if (err) { next(err, d) return false; } return _mkdirs(d, lst.slice(1), next) }) } // 返回 00::00:00 格式時間 function _timer(timer) { let nowTime = ''; let hour = 0, minute = 0, second = 0; const h = Math.floor(v / 60 / 60); hour = h >= 60 || h >= 10 ? h : '0' + h; const m = Math.floor(v / 60 % 60); minute = m >= 60 || m >= 10 ? m : '0' + m; const s = Math.floor(v % 60); second = s >= 10 ? s : '0' + s; nowTime = v >= (60 * 60) ? hour + ":" + minute + ":" + second : hour + ':' + minute + ":" + second; return nowTime; } // 排序 默認從小到大 // 用法 Array.sort( _min ) function _min(value1, value2) { if (value1 > value2) { return 1; } else if (value1 < value2) { return -1; } else { return 0; } } // 排序 默認從大到小 // 用法 Array.sort( _max ) function _max(value1, value2) { if (value1 > value2) { return -1; } else if (value1 < value2) { return 1; } else { return 0; } }