携程春招题目字符串截取和数组升维

编程风格

简单陈述一下文中代码使用的编程风格:

  1. 使用 ES5,以避免有些在线编程平台不支持 ES6 的状况(所以在这里没有用 new Set()

  2. Airbnb 代码规范,不使用单 var 模式

  3. 变量定义(var),函数体(body),return 值三者用空行隔开,逻辑鲜明

  4. 有意义的变量命名

  5. 适当的函数抽取,一个函数只做一件事情

另外还有 根据不同场合使用合适的类型判断方式

  • Array.isArray 判断数组,

  • Object.prototype.toString.call 来判断纯对象

  • typeof 判断基本类型和 function

  • instanceof 来判断自定义的对象

1. 字符串截取

题目

描述

给定一个长度小于 50 且包含字母和数字的任意字符串,要求按顺序取出当中的数字和英文字母,数字需要去重,重新排列后的字符串数字在前,字母在后。

输入

需要截取的字符串(包含数字和字母)

输出

按照要求重新排列的字符串

样例输入
'携程C2t0r1i8p2020校招'
样例输出:
'2018Ctrip'

解答

肯定有同学表示第一题不值得分析。但我还是想抛砖引玉一下,思路如下:

  1. 字符串转数组: str.split('')进而使用数组的各种操作方法,如 arr.forEach

  2. 判断字符串值是否为数字/\d/.test(element) 或者 Number.isNaN(Number(element)

  3. 判断字符串值是否为字母/[a-zA-Z]/.test(element)

  4. 数字字符串去重(利用数组去重)

  5. 输出数字+字母

由此有了这一版代码:

条件 1~3

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

2. 数组升维

题目

描述

对一维数组,根据 type 类型分组成二维数组

输入
  • 输入的参数可能是空数组 [],空对象 nullundefined,数字,字符串等异常值;

  • 也可能是结构为 [{ 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"]}]

解答

乍一看要求颇多,我们一点点来拆解:

条件 1

当输入数据不合法时,输出空数组 []

什么数据不合法?输入值不为 JSON 格式(即 array 类型)

还有呢?输入值为 JSON 格式(即 array 类型),但长度为 0;

由此写下第一句:

function groupList(list) {
  if (!Array.isArray(list) || list.length === 0) { return []; }
}
条件 2

当输入数据有效时(请先过滤数组里的异常元素)

过滤掉[],空对象 nullundefined,数字,字符串等异常元素:

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' && item !== null ? true : false;
}
条件 3(隐藏条件)

等等,结构不为 { "type": "xx", "content": "yy" } 的值,是不是也为异常元素呢?为此在 getValidItems 里加上一句:

function getValidItems(json) {
  return json.filter(function (element) {
    return isPureObject(element) && element.type && element.content;
  });
}
条件 4

过滤完成后,将相同 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 ...;
}
条件 5

貌似我们已经完成了将相同 type 值合并这一步骤,但是

注意,输出的是一个标准 JSON 格式

而且当前的结构是 {type1: contentsArr1, type2: contentsArr2} 的结构,与题目要求的:[ {type1: contentsArr1}, {type1: contentsArr2}] 不相同。

不难,再加一步便是:

function jsonResultGenerator(obj) {
  var result = [];

  Object.keys(obj).forEach(function (key) {
    result.push({ type: key, contents: obj[key] });
  });

  return result;
}
最终解答

完整的代码:

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 jsonResultGenerator(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' && item !== null ? true : false;
}

function jsonResultGenerator(obj) {
  var result = [];

  Object.keys(obj).forEach(function (key) {
    result.push({ type: key, contents: obj[key] });
  });

  return result;
}

// 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"]}]

总结

回到文章题目本身上来,什么算是有趣的前端笔试题

  • 不是固定套路的,不考“背诵能力”的

  • 体现 JS 能力的,考察点广泛全面

  • 和前端密切相关的和实际开发有联系

  • 注重细节复杂度,而不是纯粹的“算法复杂度”(仅针对前端开发,仅为博主一家之言)

如果是现场面试手写编程题,我觉得应该再加上一条:

  • 体现编程素养的,注重纵向拓展

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值