目錄:
數(shù)組扁平化
數(shù)組亂序
reduce()的妙用
git復習:rebase映凳,cherry-pick
(1)數(shù)組扁平化
1. flat()
- Array.prototype.flat()
- 參數(shù)是:要拉平的層數(shù)
- 參數(shù)是 Infinity 時表示不管嵌套多少層录别,都轉(zhuǎn)成一元數(shù)組
- flat() 不會改變原數(shù)組耕渴,該方法會返回一個新數(shù)組
- 如果原數(shù)組有空位拘悦,flat()方法會跳過空位
- 代碼:
const arr = [1, [2, 3, [4, 5, [6,7]]]] // [1,2,3,4,5,6,7]
const res = arr.flat(Infinity) // 參數(shù)表示展開的層數(shù),如果是Infinity表示不管多少層都轉(zhuǎn)成一元數(shù)組
console.log(res)
2. flatMap()
- flatMap()表示相對數(shù)組執(zhí)行 map() 方法橱脸,在執(zhí)行 flat()方法
- 參數(shù):第一個參數(shù)是一個遍歷函數(shù)础米,函數(shù)的參數(shù)一次是 value index array
- flatMap()方法還可以有第二個參數(shù)分苇,用來綁定遍歷函數(shù)里面的this
- flatMap()也不會改變原數(shù)組,會返回一個新的數(shù)組
- 注意:flatMap()默認之展開一層
- 代碼:
const arr = [1, 2, 3]
const res = arr.flatMap(i => [i, i*2]) // [1, 2, 2, 4, 3, 6]
// 相當于:[[1, 2], [2, 4], [3, 6]]
console.log(res)
2. 遞歸
recursion:遞歸
const arr = [1, [2, 3, [4, [5]]]]
function flat(arr) {
let result = []
for(let i = 0, len = arr.length; i < len; i++) {
if(Array.isArray(arr[i])) { // 如果還是數(shù)組椭盏,遞歸
result = result.concat(flat(arr[i]))
}
else {
result.push(arr[i])
}
}
return result
}
const res = flat(arr)
console.log(res)
3. toString
- 如果數(shù)組元素都是數(shù)值(注意所有的數(shù)組中的所有元素都要是數(shù)字)组砚,可以使用toString()
- 然而這種方法使用的場景卻非常有限吻商,如果數(shù)組是 [1, '1', 2, '2'] 的話掏颊,這種方法就會產(chǎn)生錯誤的結(jié)果。
const arr = [1, [2, 3, [4, [5]]]]
function flat(arr) {
return arr.toString().split(',').map(item => +item)
// arr.toString()數(shù)組的字符串形式艾帐,會展平乌叶。 => 1,2,3,4,5
// arr.toString().split(',')以,為分隔符柒爸,將字符串轉(zhuǎn)成數(shù)組 ["1", "2", "3", "4", "5"]
// +item相當于Number(item)
}
const res = flat(arr)
console.log(res)
4. 使用reduce()
var arr = [1, [2, [3, 4]]];
function flatten(arr) {
return arr.reduce(function(prev, next){
return prev.concat(Array.isArray(next) ? flatten(next) : next)
}, [])
// 這里指定了初始值是 []
// prev = []
// next = 1准浴,因為prev初始值是空數(shù)組,所以next的初始值是 1
// reduce((accumulate, currentValue, index, arr) => {....}, [])
// 第一個參數(shù):是一個函數(shù)
// 第一個參數(shù):累積變量捎稚,默認是數(shù)組的第一個元素
// 第二個參數(shù):當前變量乐横,默認是數(shù)組的第二個元素
// 第三個參數(shù):當前位置(當前變量在數(shù)組中的位置)
// 第四個參數(shù):原數(shù)組
// 第二個參數(shù):累積變量的初始值,注意如果指定了初始值今野,那么當前變量就從數(shù)組的第一個元素開始
}
console.log(flatten(arr))
4. 使用 ...展開運算符
let arr = [1, [2, [3, 4]]];
function flat(arr) {
while (arr.some(item => Array.isArray(item))) { // 循環(huán)判斷是不是數(shù)組葡公,是數(shù)組就展開
arr = [].concat(...arr); // 每次都扁平一層
}
return arr;
}
console.log(flat(arr))
https://github.com/mqyqingfeng/Blog/issues/36
(2)數(shù)組亂序
- shuffle:洗牌
前置知識:
1. sort()
- sort()默認是按字典就行排序,數(shù)字會先被成字符串条霜,改變原數(shù)組催什,沒有返回值
- 如果想按照自定義的方式排序,參數(shù)可以是一個函數(shù)
- 參數(shù)函數(shù)有兩個參數(shù)(兩個比較的數(shù)組成員)
- 返回值大于0宰睡,表示第一個成員排在第二個成員后面 (a-b>0蒲凶,則a排在b后面)
- 返回值小于0,表示第一個成員排在第二個成員前面
- 返回值等于0拆内,位置不變
- arr.sort((a, b) => a - b ) 升序
- arr.sort((a, b) => b - a ) 降序
2. js中不加分號的注意事項:
- 小括號開頭的前一條語句(注意前面要是語句旋圆,表達式不受影響)
- 中括號開頭的前一條語句
解決方法:在小括號或者中括號前面加上分號
哪些地方會用到亂序:
1. 換一批
2. 猜你喜歡
3. 中獎方案
方法1:
arr.sort(() => Math.random() - .5)
function a() {
const arr = [1, 2, 3, 4, 5]
arr.sort(() => Math.random() - .5) // 因為Math.random的值區(qū)間是[0, 1) 所以 這里大于0和小于0的概率都是50%
// sort自定義排序時接收一個函數(shù)作為參數(shù)
// 函數(shù)返回值大于0,表示兩個比較的成員麸恍,第一個排在第二個的后面
// 函數(shù)返回值小于0臂聋,表示兩個比較的成員,第一個排在第二個的前面
// 函數(shù)返回值等于0或南,表示兩個比較的成員孩等,位置不變
// 當小數(shù)是0點幾時,可以省略前面的0
console.log(arr)
}
-----------
存在問題:
1. 概率不均等
2. 造成概率不均等的原因是采够,sort底層實現(xiàn)是用了插入排序
3. 具體就是當無序部分插入到有序部分的元素肄方,一旦找到位置,剩下的元素就沒有在和緩存的值就行比較了
4. 沒有機會比較所有元素蹬癌,所以得不到完全隨機的結(jié)果
如下:
const times = [0, 0, 0, 0, 0, 0]
for(i = 0; i < 100000; i++) {
const arr = [1, 2, 3, 4, 5, 6]
arr.sort(() => Math.random() - 0.5)
times[arr[5] - 1] ++
// times[arr[5] - 1] ++ 表示arr數(shù)組最后一個位置上权她,各數(shù)字出現(xiàn)的次數(shù)
// 當arr[5]是6時虹茶,times[5]位置的值+1,就是arr[5]是6的次數(shù)+1
}
console.log(times)
// [19480, 5174, 15619, 14188, 18880, 26659] 概率分配不均隅要,arr[5]是2的概率明顯小了很多
-----------
sort排序源碼:
- 各個瀏覽器的sort()方法的實現(xiàn)方法不同
- v8中
- 當數(shù)組長度小于10時蝴罪,用的是插入排序
- 否則,使用的是插入排序和快速排序的混合排序
-----------
插入排序
- 分類:
- 直接插入排序:順序發(fā)定位插入位置
- 二分插入排序:二分法定位插入位置
- 希爾排序 :縮小增量步清,多遍插入排序
-----------
直接插入排序:
- 插入排序的思想:從無序數(shù)組中取出一個值要门,插入到有序數(shù)組中,插入后有序數(shù)組仍然有序(打牌)
- 原理:
1. 將數(shù)組分成兩部分廓啊,左邊是有序數(shù)組(最初只有一個元素)欢搜,右邊是無序數(shù)組(所以循環(huán)是從1開始,因為有序部分初始有一個元素)
2. 從右邊的無序部分依次取出一個值谴轮,插入到有序部分炒瘟,直到取完無序部分
3. 如果找有序部分的插入位置?:
1. 先緩存需要插入的無序部分的值第步,用一個變量來緩存 let temp = arr[i]
2. 從有序部分的最后位置找(arr[i - 1])疮装,如果arr[i - 1] > arr[i] 則該元素往后移動一位
3. 如果有序該位置仍然比需要插入的值大,有序中該位置的值粘都,也后移動一位廓推,直到 j>=0
- 代碼:
// 直接插入排序
const arr = [1, 4, 3, 2]
const insert_sort = (arr) => {
for(let i = 1, len = arr.length; i < len; i++) { // 循環(huán)數(shù)組的無序部分,從1開始驯杜,因為假設(shè)初始化時有序部分有一個元素
let temp = arr[i] // 緩存需要插入有序部分的這個無序部分的值受啥,因為有序部分可能會往后移動位置,將其覆蓋
let j = i - 1 // 有序部分的最后一個元素的位置鸽心,有序部分從最后的位置依次往前查找需要插入的位置
while(j >= 0 && arr[j] > temp) { // 有序部分循環(huán)條件
arr[j+1] = arr[j] // 有序該位置值大于temp滚局,則往后移動一位
j-- // 依次往前查找
}
arr[j+1] = temp // 循環(huán)完后,j+1就是需要插入的位置顽频,因為條件是大于temp藤肢,不滿足時,j+1就是要插入的位置
}
return arr // 最后返回數(shù)組
}
console.log(insert_sort(arr))
亂序排序改進
Fisher–Yates
1. 使用sort(() => Math.random() - .5)存在的問題就是不能完全實現(xiàn)全部元素的比較糯景,造成概率不均等
2. 為什么叫 Fisher–Yates 呢嘁圈?
- 因為這個算法是由 Ronald Fisher 和 Frank Yates 首次提出的。
3.shuffle:是洗牌的意思
4.Fisher–Yates的原理:
- 首先選润盎础(數(shù)組最后一個位置)的元素和(數(shù)組長度隨機位置)上的元素交換
- 接著選茸钭 (數(shù)組倒數(shù)第二個位置)的元素和(除去最后一個位置剩下的數(shù)組位置)上的元素交換
- 重復以上步驟,直到length >= 1
5.代碼
// 數(shù)組亂序
const arr = [1, 2, 3, 4, 5, 6]
function shuffle(arr) {
let length = arr.length
while(length > 1) {
const pivot = Math.floor(Math.random() * length--)
// 1. 注意這里是先賦值怠惶,再減 1涨缚,即Math.floor(Math.random() * 6)
// (Math.random() * 6的區(qū)間[0, 6)
// Math.floor(Math.random() * 6) 區(qū)間是 [0-5]
// 2. 語句以分號結(jié)尾,一個分號就表示一個語句結(jié)束策治。所以這里賦值語句后面記得加分號
// 3. ;[arr[pivot], arr[length]] = [arr[length], arr[pivot]]這里條語句前加上分號脓魏,因為前面也是語句
// 在小括號開頭兰吟,或者中括號開頭的語句,前面的語句末尾需要加分號茂翔,或者加到本條語句前面
//4. const pivot = Math.floor(Math.random() * length--); 這樣也行
;[arr[pivot], arr[length]] = [arr[length], arr[pivot]] // 這里的length是減1之后的length
// const temp = arr[length]
// arr[length] = arr[pivot]
// arr[pivot] = temp
}
return arr
}
console.log(shuffle(arr))
https://juejin.im/post/5d004ad95188257c6b518056#heading-2
(3)reduce()使用技巧
reduce()
(1) 概念
- reduce()默認按照字典排序
- reduce(function(reduce, currentValue, currentIndex, arr), initial)
- 第一個參數(shù)是函數(shù):
- 函數(shù)第一個參數(shù):累計變量混蔼,默認是數(shù)組的第一項
- 函數(shù)第二個參數(shù):當前變量,默認是數(shù)組的第二項(如給定reduce第二個參數(shù)(累積變量初始值)珊燎,則當前變量從第一項開始)
- 函數(shù)第三個參數(shù):當前位置惭嚣,(第二個參數(shù)的下標)
- 函數(shù)第四個參數(shù):原數(shù)組
- 第二個參數(shù)是(累計變量初始值),如果給定累計變量初始值俐末,當前變量就從數(shù)組第一項開始
(2) 用法
1. 累加
2. 將數(shù)組轉(zhuǎn)化成對象
const arr = [{id: 1, name: 'wang'}, {id: 2, name: 'zhang'}]
const res = arr.reduce((pre, cur, i, arr) => {
return {...pre, [cur.id]: cur}
}, {})
console.log(res)
(3) 實現(xiàn)數(shù)組扁平化
const arr = [1, [2, [3, [4, 5]], 6], 7]
function flat(arr) {
return arr.reduce((prev, current, index, arr) => {
return prev.concat(Array.isArray(current) ? flat(current) : current)
}, [])
}
const res = flat(arr)
console.log(res)
https://juejin.im/post/5cbc23def265da037b610ec6#heading-18
https://juejin.im/post/5d073414f265da1b6029037f
(4)git
(一)初次運行g(shù)it前的配置
(1) 用戶信息
- 第一步就是設(shè)置(用戶名)和(郵件地址)
- 如果使用了--global料按,該命令只需運行一次奄侠,之后無論在什么系統(tǒng)上做任何事情卓箫,git都會使用那些信息
- 當你想針對特定項目使用不同的用戶名稱與郵件地址時,可以在那個項目目錄下運行沒有 --global 選項的命令來配置垄潮。
$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com
(2) 文本編輯器
- 當用戶信息配置完后烹卒,可以配置文本編輯器,用戶使用git輸入信息時弯洗,會調(diào)用文本編輯器
- 默認調(diào)用的是 (vim)旅急,如果想自定義可以輸入以下命令:
$ git config --global core.editor emacs // 使用Emacs編輯器
(3) 檢查配置信息
- 如果想要檢查你的配置,可以使用 git config --list 命令來列出所有 Git 當時能找到的配置
$ git config --list
(1) git log
- git log:顯示從最近到最遠的提交日志
- git log --pretty=oneline --graph
- // --pretty=oneline 將commit 信息簡化成一行顯示
- // --graph命令可以看到分支合并圖牡整。 -------------( graph是圖表的意思 )
(2) git reflog
- gitt reflog:記錄幾乎所有本地倉庫的改變
- 可以用來重返未來(git reset --hard comit_id之后后悔)
(3) git reset
- git reset --hard commit_id
- git reset --hard HEAD^ // 回退到上一個commit
- 當前版本 ( HEAD )
- 上一個版本 ( HEAD^ )或者 ( HEAD~1 )
- 上上個版本 ( HEAD^^ ) 或者 ( HEAD~2 )
(4) git rebase
- 不同分支:變基
- 同一分支:合并多個提交
git rebase變基
- 不同分支的處理是變基
- git rebase master // 把當前分支變基到master分支
git rebase進入交互模式
- 同一分支是進入交互模式
- git rebase -i [startpoint] [endpoint]
- git rebase -i HEAD~3 表示將最新的三個提交進入交互式界面
// [startpoint] [endpoint]這個是一個 (前開后閉區(qū)間)
// 如果不指定[endpoint]藐吮,則該區(qū)間的終點默認是當前分支HEAD所指向的commit(
// i:是 (interactive)交互的意思
pick:保留該commit(縮寫:p)
reword:保留該commit,但我需要修改該commit的注釋(縮寫:r)
edit:保留該commit, 但我要停下來修改該提交(不僅僅修改注釋)(縮寫:e)
squash:將該commit和前一個commit合并(縮寫:s)
fixup:將該commit和前一個commit合并逃贝,但我不要保留該提交的注釋信息(縮寫:f)
exec:執(zhí)行shell命令(縮寫:x)
drop:我要丟棄該commit(縮寫:d)
- squash:是粉碎的意思
- reword:改寫谣辞,修改措辭的意思
http://www.reibang.com/p/4a8f4af4e803
(5) git cherry-pick 摘櫻桃
- git cherry-pick:把其他分支的commit,移到當前分支
- git cherry-pick <commit id>
- 如果有沖突沐扳,首先需要解決沖突,解決沖突后需要git commit手動進行提交
- git add .后直接使用git cherry-pick --continue繼續(xù) // 繼續(xù)后泥从,可以修改提交的commit的命名