认真编写的题目能测出代码水平,而有趣的题目则能激发人的“代码欲望”。前端
先后参加过网易、美团、头条、滴滴等公司的在线编程题。简单的认为题目大致有如下三种类型: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)
的判断) - =(相信有很多同窗也是这样),没有时间把第三题撸出来了。。。