認真編寫的題目能測出代碼水平,而有趣的題目則能激發人的「代碼慾望」。前端
先後參加過網易、美團、頭條、滴滴等公司的在線編程題。簡單的認爲題目大致有如下三種類型:git
筆試題在不少時候確實是個「坑」,能避開就避開,由於畢竟像情況 2 的是少數。但優質的題目確實是一個很好的編程能力檢驗,遇到了就不要錯過。github
2018 年春招的攜程前端筆試題是一個不錯的例子,下面對其中的編程題作一番分析。面試
P.S. 原文顯示效果更好喔:) check:rayjune.me/有趣的前端編程題算法
做者:RayJune(轉載請署名,請尊重博主含辛茹苦、遍查資料、一行一行含淚碼出來的成果)spring
簡單列舉一下可能被問到的問題:編程
很是肯定 100% AC。同時這意味着細節複雜度上的處理到位。(實際前端開發中要處理大量細節複雜度的東西,這一樣頗有意思)json
避免有些筆試平臺不支持 ES6 的情況,你懂的數組
new Set()
來去重呢?同上,另外順便回顧一下數組去重。在面試的時候寫 new Set
來數組去重會被 diss 的,別問我爲何知道 :>函數式編程
一種編程品味。
簡單陳述一下文中代碼使用的編程風格:
ES5
,以免有些在線編程平臺不支持 ES6
的情況(因此在這裏沒有用 new Set()
)var
模式var
),函數體(body
),return
值三者用空行隔開,邏輯鮮明另外還有 根據不一樣場合使用合適的類型判斷方式:
Array.isArray
判斷數組,Object.prototype.toString.call
來判斷純對象typeof
判斷基本類型和 function
instanceof
來判斷自定義的對象給定一個長度小於 50 且包含字母和數字的任意字符串,要求按順序取出當中的數字和英文字母,數字須要去重,從新排列後的字符串數字在前,字母在後。
須要截取的字符串(包含數字和字母)
按照要求從新排列的字符串
'攜程C2t0r1i8p2020校招'
複製代碼
'2018Ctrip'
複製代碼
確定有同窗表示第一題不值得分析。但我仍是想拋磚引玉一下,思路以下:
str.split('')
(進而使用數組的各類操做方法,如 arr.forEach
)/\d/.test(element)
或者 Number.isNaN(Number(element)
/[a-zA-Z]/.test(element)
由此有了這一版代碼:
function handleStr(str) {
var arr = str.split('');
var nums = '';
var words = '';
arr.forEach(function (element) {
if (/\d/.test(element))) {
nums += element;
} else if (/[a-zA-Z]/.test(element) ) {
words += element;
}
});
return uniqueStr(nums) + words;
}
複製代碼
做爲前端開發超高頻面試題,相信你們早已對數組去重熟捻於心:
基本類型去重:
function unique(arr) {
return arr.filter(function (element, index) {
return arr.indexOf(element) === index;
});
}
複製代碼
基本+複雜類型去重:
function unique(arr) {
var hash = {};
return arr.filter(function (element) {
if (hash.hasOwnProperty(element)) {
return false;
}
hash[element] = true;
return true;
});
}
複製代碼
因爲數字去重(str
,基本類型)基於數組去重,咱們要對原來的數組去重作一點修改:
function uniqueStr(str) {
var arr = str.split('');
return arr.filter(function (element, index) {
return arr.indexOf(element) === index;
}).join('');
}
複製代碼
string.split()
和 array.join()
幫助咱們自由的遊走在字符串和數組間。
function handleStr(str) {
var arr = str.split('');
var nums = '';
var words = '';
arr.forEach(function (element) {
if (/\d/.test(element)) {
nums += element;
} else if (/[a-zA-Z]/.test(element) ) {
words += element;
}
});
return uniqueStr(nums) + words;
}
function uniqueStr(str) {
var arr = str.split('');
return arr.filter(function (element, index) {
return arr.indexOf(element) === index;
}).join('');
}
// 測試
console.log(handleStr('攜程C2t0r1i8p2020校招'));
// 2018Ctrip
複製代碼
很是感謝評論區 @while大水逼 大神的寶貴建議,博主筆試的時候沒想到 str.match(regex)
的方法。實現更簡潔、邏輯的展現更好,在此補上:
function handleStr(str) {
var nums = str.match(/\d/g).join('');
var words = str.match(/[a-zA-Z]/g).join('');
return uniqueStr(nums) + words;
}
function uniqueStr(str) {
var arr = str.split('');
return arr.filter(function (element, index) {
return arr.indexOf(element) === index;
}).join('');
}
// 測試
console.log(handleStr('攜程C2t0r1i8p2020校招'));
// 2018Ctrip
複製代碼
對一維數組,根據 type
類型分組成二維數組
[]
,空對象 null
,undefined
,數字,字符串等異常值;[{ type, content}]
的有效值;[null, null, (type, content)]
等有效和非法值混合的數據。[]
type
值的元素合併,造成新元素 {"type": "A", "contents": [content1, content2]}
,其中,contents
爲一個數組,元素爲全部 type 值相同的 content
值。JSON
格式var input = [null, 2, "test", undefined, {
"type": "product",
"content": "product1"
}, {
"type": "product",
"content": "product2"
}, {
"type": "tag",
"content": "tag1"
}, {
"type": "product",
"content": "product3"
}, {
"type": "tag",
"content": "tag2"
}];
複製代碼
[{"type":"product","contents":["product1","product2","product3"]},{"type":"tag","contents":["tag1","tag2"]}]
複製代碼
乍一看要求頗多,咱們一點點來拆解:
當輸入數據不合法時,輸出空數組
[]
什麼數據不合法?輸入值不爲 JSON
格式(即 array
類型);
還有呢?輸入值爲 JSON
格式(即 array
類型),但長度爲 0
;
由此寫下第一句:
function groupList(list) {
if (!Array.isArray(list) || list.length === 0) { return []; }
}
複製代碼
當輸入數據有效時(請先過濾數組裏的異常元素)
過濾掉[]
,空對象 null
,undefined
,數字,字符串等異常元素:
function groupList(list) {
if (!Array.isArray(list) || list.length === 0) { return []; }
var validItems = getValidItems(list);
}
function getValidItems(json) {
return json.filter(function (element) {
return isPureObject(element)
});
}
function isPureObject(item) {
return Object.prototype.toString.call(item).slice(8, -1) === 'Object';
}
複製代碼
且慢,結構不爲 { "type": "xx", "content": "yy" }
的值,是否是也爲異常元素呢?爲此在 getValidItems
里加上一句:
function getValidItems(json) {
return json.filter(function (element) {
return isPureObject(element) && element.type && element.content;
});
}
複製代碼
可能有同窗會問,這裏爲何不用 typeof
判斷 object
,而是那麼麻煩擼了一個 isPureObject
呢?
首先明確 typeof
用來判斷基本類型和 function
(check: 根據不一樣場合使用合適的類型判斷方式),舉個例子:
var demo = [1, 2];
demo.type = '我實際上是數組';
demo.content = '但我也有 type 和 content 屬性,判斷不出來了吧';
複製代碼
若是是
function getValidItems(json) {
return json.filter(function (element) {
return typeof element === 'object' && element.type && element.content;
});
}
複製代碼
顯然沒法過濾 demo
這種狀況了,更況且還能夠是 regex 等各類非 function
的對象。
因此在線編程題請慎重考慮邊緣狀況。
過濾完成後,將相同
type
值的元素合併,造成新元素
function groupList(list) {
if (!Array.isArray(list) || list.length === 0) { return []; }
var validItems = getValidItems(list);
var result = {};
validItems.forEach(function (item) {
if (result.hasOwnProperty(item.type)) {
result[item.type].push(item.content);
} else {
result[item.type] = [];
result[item.type].push(item.content);
}
});
return result;
}
複製代碼
貌似咱們已經完成了將相同 type
值合併這一步驟,可是:
當前的結構是 {type1: contentsArr1, type2: contentsArr2}
的結構,與題目要求的:[{type1: contentsArr1}, {type1: contentsArr2}]
不相同。
不難,再加一步即是:
function adjustFormat(obj) {
var result = [];
Object.keys(obj).forEach(function (type) {
result.push({ type: type, contents: obj[type] });
});
return result;
}
複製代碼
且慢,根據一個數組產生一個新的數組,用 array.map
是否是更物盡其用呢?(再次感謝評論區 @while大水逼 提出的方案)
更純粹的函數式編程,更直觀的邏輯展現:
function adjustFormat(obj) {
return Object.keys(obj).map(function (type) {
return { type: type, contents: obj[type] };
});
}
複製代碼
完整的代碼:
function groupList(list) {
if (!Array.isArray(list) || list.length === 0) { return []; }
var validItems = getValidItems(list);
var result = {};
validItems.forEach(function (item) {
if (result.hasOwnProperty(item.type)) {
result[item.type].push(item.content);
} else {
result[item.type] = [];
result[item.type].push(item.content);
}
});
return adjustFormat(result);
}
function getValidItems(json) {
return json.filter(function (element) {
return isPureObject(element) && element.type && element.content;
});
}
function isPureObject(item) {
return Object.prototype.toString.call(item).slice(8, -1) === 'Object';
}
function adjustFormat(obj) {
return Object.keys(obj).map(function (type) {
return { type: type, contents: obj[type] };
});
}
// test
var input = [null, 2, "test", undefined, {
"type": "product",
"content": "product1"
}, {
"type": "product",
"content": "product2"
}, {
"type": "tag",
"content": "tag1"
}, {
"type": "product",
"content": "product3"
}, {
"type": "tag",
"content": "tag2"
}];
console.log(JSON.stringify(groupList(input)));
// [{"type":"product","contents":["product1","product2","product3"]},{"type":"tag","contents":["tag1","tag2"]}]
複製代碼
回到文章題目自己上來,什麼算是有趣的前端筆試題?
若是是現場面試手寫編程題,我以爲應該再加上一條:
若是哪家公司有這樣的編程題,請把我一波流內推帶走 :)
更多信息,check: rayjune.me/about
有同窗問爲神馬沒有第三題的題解,由於本身在第二題的細節複雜度中消耗了大量時間(盯了一二十分鐘才發現須要進行 Array.isArray(input)
的判斷) - =(相信有很多同窗也是這樣),沒有時間把第三題擼出來了。。。