第 152 题:实现一个 normalize 函数,能将输入的特定的字符串转化为特定的结构化数据
gauseen opened this issue · comments
字符串仅由小写字母和 [] 组成,且字符串不会包含多余的空格。
示例一: 'abc' --> {value: 'abc'}
示例二:'[abc[bcd[def]]]' --> {value: 'abc', children: {value: 'bcd', children: {value: 'def'}}}
let normalize = str => {
let result = {}
let c
// 字符串转化为数组
let arr = str.split(/[\[\]]/g).filter(Boolean)
// 生成结构化数据
arr.forEach((item, index) => {
if(index != 0) {
c.children = {}
c.children.value = item
c= c.children
} else {
result.value = item
c= result
}
})
return result
}
let str = '[abc[bcd[def]]]'
normalize(str)
// {value: 'abc', children: {value: 'bcd', children: {value: 'def'}}}
const normalize = (str) => {
var result = {}
str.split(/[\[\]]/g).filter(Boolean).reduce((obj, item, index, a) => {
obj.value = item
if(index !== a.length -1) {
return (obj.children = {})
}
}, result)
return result
}
function normalize(str) {
let arr = str.match(/\w+/g)
let temp = {}
let obj
while(arr.length) {
let item = arr.pop()
temp.value = item
obj && (temp.children = obj)
if(arr.length) {
obj = {...temp}
temp = {}
}else {
obj = temp
}
}
return obj
}
const normalize = str => {
const arr = str.split(/[\[\]]/).filter(Boolean);
const createArr = arr => {
return arr.reduce((obj, val, n, arr) => {
arr.length > 1 ? (obj.children = createArr(arr.slice(1))) : "";
obj.value = arr[0];
return obj;
}, {});
};
return createArr(arr);
};
var normalize = (str) => {
var list = str.match(/\w+/g)
var obj = {}
var curr = obj
while (key = list.shift()) {
curr.value = key
if (list.length === 0) break
curr.children = {}
curr = curr.children
}
return obj
}
字符串仅由小写字母和 [] 组成,且字符串不会包含多余的空格。
示例一: 'abc' --> {value: 'abc'}
示例二:'[abc[bcd[def]]]' --> {value: 'abc', children: {value: 'bcd', children: {value: 'def'}}}
let normalize = (str) => {
let arr = str.split(/[\[\]]/).filter(Boolean);
let i = 0, obj = {}, cur = obj;
while(i < arr.length) {
if (i > 0) cur = cur.children = {};
cur.value = arr[i];
i ++;
}
return obj;
}
function normalize(str, res = {}) {
if (str) {
if (str[0] === "[") {
const exec = /^\[(\w+)(\[.*\]){0,1}\]$/.exec(str);
if (exec) {
const [, value, next] = exec;
res.value = value;
next && normalize(next, (res.children = {}));
}
} else if (!/(\[|\])/.test(str)) {
res.value = str;
}
}
return res;
}
// 测试用例
[
"[a[b[c]]]",
"",
"asd",
"[aads",
"asdasd]",
"[asddd]",
"[a[d]",
"[s[]]"
].reduce((acc, c) => ((acc[c] = normalize(c)), acc), {});
es5、纯算法:
function normalize(str) {
if (!/(\[|\])/.test(str)) {
return { value: str };
}
var len = str.length,
quene = [],
res = {},
ret = res,
current = "";
for (var i = 0; i < len; i++) {
var c = str[i];
if (c === "[" || c === "]") {
if (current) {
quene.push(current);
current = "";
}
if (c === "]") {
var top = quene.shift();
if (top) {
res.value = top;
if (quene.length) {
res = res.children || (res.children = {});
}
}
}
} else {
current += c;
}
}
return ret;
}
function normalize(str) {
if (!str) return {};
const arr = str
.split(/[\[\]]/g)
.filter(Boolean)
.reverse();
return arr.reduce((acc, cur) => {
const temp = {};
if (acc.value) { //说明此时acc !== {}
temp.children = acc;
}
temp.value = cur;
return temp;
}, {});
}
function normalize(str) {
let current, result;
while (current = str.match(/\[([a-z]+)\]/)) {
let [res, value] = current;
result = result ? { value, children: result } : { value };
str = str.replace(res, '');
}
if (!result) result = {value: str};
return result;
}
function normalize(str) {
const list = str.match(/\w+/g)
function fn(list) {
if(list.length === 1){
return {
value: list[0]
}
}
let res = {}
const item = list.shift();
res = {
value: item,
children: fn(list)
}
return res
}
return fn(list)
}
var str = '[abc[bcd[def]]]';
console.log(fn(str));
function fn(strs) {
var arr = strs.replace('[', '').replace(/]/g, '').split('[');
// console.log('arr: ', arr);
var res = {};
var pointer = res;
for (var i = 0; i < arr.length; i ++) {
pointer.value = arr[i];
if (i < arr.length - 1) {
pointer.children = {};
pointer = pointer.children;
}
}
return res;
}
function normalize(s) {
let arr = s.match(/\w+/g)
let result
while(arr.length) {
let cur = arr.pop()
let temp = {value: cur}
if(result) {
temp.children = result
}
result = temp
}
return result
}
// 测试
var s = 'abc'
normalize(s) // {value: "abc"}
s = '[abc[bcd[def]]]'
normalize(s)
// {value: 'abc', children: {value: 'bcd', children: {value: 'def'}}}
更过编程算法题可见 JavaScript-Algorithms
return (obj.children = {})
return (obj.children = {}) 这个啥意思 呀 还是看不懂 为啥
return (obj.children = {})return (obj.children = {}) 这个啥意思 呀 还是看不懂 为啥
简化一下代码,你可以这么理解:
const normalize = (str) => {
var result = {};
str
.split(/[\[\]]/g)
.filter(Boolean)
.reduce((obj, item) => {
obj.value = item;
let children = {};
obj.children = children;
return children;
}, result);
return result;
};
return (obj.children = {})return (obj.children = {}) 这个啥意思 呀 还是看不懂 为啥
简化一下代码,你可以这么理解:
const normalize = (str) => { var result = {}; str .split(/[\[\]]/g) .filter(Boolean) .reduce((obj, item) => { obj.value = item; let children = {}; obj.children = children; return children; }, result); return result; };
代码写的6,顶一个,但是用这种极简的*操作写法是为了减少代码量么,可读性不考虑么😅
const normalize = str => { const arr = str.split(/[\[\]]/).filter(Boolean); const createArr = arr => { return arr.reduce((obj, val, n, arr) => { arr.length > 1 ? (obj.children = createArr(arr.slice(1))) : ""; obj.value = arr[0]; return obj; }, {}); }; return createArr(arr); };
你用了递归,你的reduce没有任何意义, 但是我没有证据
const normalize = function(str) {
let res = {}
str.split(/[\[\]]/).filter(Boolean).reduce((prev, curr, index) => {
if (index) prev = prev['children'] = {}
prev['value'] = curr;
return prev
}, res)
return res
}
const normalize = (str = '') =>
str
.split(/[\[\]]/g)
.filter(Boolean)
.reverse()
.reduce((acc, cur, index) => (!index ? { value: cur } : { value: cur, children: acc }), {});
let str1 = '[abc[bcd[def]]]',
str2 = 'abc';
console.log(normalize(str1));
console.log(normalize(str2));
正则真香
const normalize = (str) => {
const result = {}
str.match(/(?=\w)\w+/g).reduce((total,current,index,arr)=>{
total.value = current
if(index < arr.length -1) {
return (total.children = {})
}
},result)
return result
}
都在正则,来个不用正则的:
/**
* 第 152 题:实现一个 normalize 函数,能将输入的特定的字符串转化为特定的结构化数据
* 字符串仅由小写字母和 [] 组成,且字符串不会包含多余的空格。
* 示例一: 'abc' --> {value: 'abc'}
* 示例二:'[abc[bcd[def]]]' --> {value: 'abc', children: {value: 'bcd', children: {value: 'def'}}}
*
* @version 2020-8-11
*/
const CHILDREN_START = Symbol();
const CHILDREN_END = Symbol();
const VALUE = Symbol();
const EOF = Symbol();
function scanner(s) {
let pos = 0;
return {
[Symbol.iterator]() {
return this;
},
next() {
let token = {
value: "",
type: EOF,
done: true,
};
for (; pos < s.length; ) {
let c = s.charAt(pos++);
switch (c) {
case "'":
continue;
case "[":
token.value = "[";
token.type = CHILDREN_START;
token.done = false;
return token;
case "]":
token.value = "]";
token.type = CHILDREN_END;
token.done = false;
return token;
default:
token.type = VALUE;
token.done = false;
token.value += c;
while (pos < s.length) {
c = s.charAt(pos++);
if (["'", "[", "]"].includes(c)) {
pos--;
break;
}
token.value += c;
}
return token;
}
}
return token;
},
};
}
function normalize(str) {
const scan = scanner(str);
let obj = {};
let temp = obj;
for (let v = scan.next(); !v.done; v = scan.next()) {
switch (v.type) {
case CHILDREN_START:
temp.children = {};
temp = temp.children;
break;
case VALUE:
temp.value = v.value;
break;
}
}
if (!obj.value) {
obj = obj.children;
}
return obj;
}
console.log(JSON.stringify(normalize("[abc[bcd[def]]]"))); // => {"value":"abc","children":{"value":"bcd","children":{"value":"def"}}}
console.log(JSON.stringify(normalize("abc"))); // => {"value":"abc"}
/**
* 递归版本
* @param {string} str
*/
export function normalizeRecur(str) {
const matchRe = /^\[.*\]$/
const valueRe = /^\[([^\[\]]*)/
let root = {}
if (matchRe.test(str)) {
root.value = str.match(valueRe)[1]
root.children = normalize(str.slice(1 + root.value.length, str.length - 1))
} else if (str.length > 0) {
root.value = str
} else {
root = undefined
}
return root
}
/**
* 非递归版本
* @param {string} str
*/
export function normalize(str) {
const stack = []
const startRe = /^\[/
const endRe = /^\]/
const valueRe = /^\[([^\[\]]*)/
let root
let parent
while(str) {
if(startRe.test(str)) {
let valueMatch = str.match(valueRe)
let cur = {}
root = root || cur
if (parent) parent.children = cur
cur.value = valueMatch[1]
stack.push(cur)
parent = cur
str = str.slice(valueMatch[0].length)
} else if (endRe.test(str)) {
str = str.slice(1)
stack.pop()
}
}
return root
}
function normalize(str) {
var array = str.match(/[a-z]+/g);
var obj = {};
array.reduce((acc, cur, index) => {
const isInLast = index == array.length - 1;
acc.value = cur;
if (!isInLast) {
acc.children = {}
}
return isInLast ? acc : acc.children
}, obj);
return obj;
}
normalize('abc')
normalize('[abc[bcd[def]]]')
function normalize(str) {
let len = str.length, stack = [], j = 0
for (let i = 0; i < len; i++) {
if (str[i] === '[') {
j++
} else if (str[i] === ']') {
j--
} else {
if (!stack[j]) {
stack[j] = ''
}
stack[j] = stack[j] + str[i]
}
}
if (stack.length && stack[0] === undefined) {
stack.shift()
}
let root = {}, temp = root
for (let i = 0; i < stack.length; i++) {
temp.value = stack[i]
if (i !== stack.length - 1) {
temp.children = {}
temp = temp.children
}
}
return root
}
function normalize(str) {
let arr = str.split(/[\[\]]/g).filter(Boolean);
if(arr.length === 1) return {value:arr[0]}
return arr.reduceRight(function(pre, curr, idx) {
pre.value = curr
return idx > 0 ? {chiledren: pre} : pre
}, {})
}
我想说,以上考虑过这种情况么
'[abc[bcd[def]ghi[jkl]]'
还是说这种嵌套的不在考虑范围内
function normalize(str) {
const arr = str.split(/[[\]]/).filter(Boolean) // str.split(']').join('').split('[').filter(Boolean)
return arr.length > 1
? arr.reverse().reduce((acc, cur, index) => ({
value: cur,
children: index === 1 ? { value: acc } : acc
}))
: { value: str }
}
function parse(str){
const list = str.split(/(\[|\])/).filter(val =>val);
let result = null;
let temp = null;
for(let i = 0, len = list.length; i< len; i++){
const value = list[i];
if(value == ']'){
break;
}
switch(value){
case '[':
if(result){
result = (result.children || (result.children = {}));
}else{
result = temp = {};
}
break;
default:
if(result){
result.value = value;
}else{
result = temp = { value: value};
}
break;
}
}
return temp;
}
function normalize(str) {
let res = str.match(/\[(.+?)\]/);
let p = res ? res[1] : str;
let arr = p.split('[');
var obj = {};
var cur = obj;
for (let i = 0; i < arr.length; i++) {
if (i > 0) {
cur.children = {value: arr[i]}
cur = cur.children
} else {
cur.value = arr[i];
}
}
return obj;
}
function normalize(str) {
let arr = str.split(/[\[\]\s]+/).filter(Boolean);
let result = {};
arr.reduce((pre, next) => (pre.children = { value: next }), result);
return result.children;
}
// 字符串仅由小写字母和 [] 组成,且字符串不会包含多余的空格。
// 示例一: 'abc' --> {value: 'abc'}
// 示例二:'[abc[bcd[def]]]' --> {value: 'abc', children: {value: 'bcd', children: {value: 'def'}}}
function format(str) {
const stack = []
let i = 0
let result
while (i < str.length) {
switch (str[i]) {
case "[":
i++
break;
case "]":
i++
stack.pop()
break;
default:
let val = str[i];
i++
while (!['[', ']'].includes(str[i]) && i < str.length) {
val += str[i];
i++
}
const node = { val };
if (!stack.length) {
result = node
}
if (stack.length && stack.length - 1 < stack.length) {
stack[stack.length - 1].children =
stack[stack.length - 1].children || [];
stack[stack.length - 1].children.push(node);
}
stack.push(node);
}
}
return result;
}
console.log("format", format("[abc[bcd[def]]]"));
console.log("format", format("[abc[bcd[def][1]][2]]"));
function normalize(str) {
let obj = {};
const vals = str.split(/[\[\]]/g).filter(Boolean);
for (let i = vals.length - 1; i >= 0; i--) {
!obj.value ? obj.value = vals[i] : obj = {
value: vals[i],
children: {
...obj
}
}
}
return obj
}
用 reduce
搞定
function normalize(input) {
const arr = input.replace(/\[|\]/g, ',').split(',').filter(itm => itm);
let result = {};
arr.reduce((obj, cur, idx) => {
const temp = {};
temp.value = cur;
if (obj.children) obj.children = temp;
if (idx !== arr.length - 1) temp.children = {};
if (idx === 0) result = temp;
return temp;
}, result);
return result;
}
console.log(normalize('abc'));
console.log(normalize('[abc[bcd[def]]]'));
用栈实现
function normalize(str) {
const stack = [];
let res = {};
for (let c of str) {
if (c === ']') {
let value = [];
let top = stack.pop();
while (top !== '[') {
value.unshift(top);
top = stack.pop();
}
if (res.value) {
res.children = { ...res };
}
res.value = value.join('');
continue;
}
stack.push(c);
}
if (stack.length) {
res.value = stack.join('');
}
return res;
}
es6实现
function normalize(str) {
let obj = {};
let arr = str.split(/[\[\]]/g).filter(Boolean);
arr.reduce((acc, cur) => {
while (acc.children) {
acc = acc.children;
}
acc.value = cur;
acc.children = {};
return acc;
}, obj);
return obj;
}
es5实现
function findChild(obj) {
return obj.children ? findChild(obj.children) : obj;
}
function normalize2(str) {
let arr = str.split(/[\[\]]/g).filter(Boolean);
let res = {};
while ((item = arr.shift())) {
let obj = findChild(res);
obj.value = item;
obj.children = {};
}
return res;
}
上面同学的测试用例
let arr = [
"[a[b[c]]]",
"",
"asd",
"[aads",
"asdasd]",
"[asddd]",
"[a[d]",
"[s[]]",
];
arr.reduce((acc, c) => ((acc[c] = normalize(c)), acc), {});
reverse 倒著回來
function normalize(str) {
const arr = str.replaceAll(']', '').split('[').filter(Boolean)
const res = arr.reverse().reduce((obj, value, idx, a) => {
if (idx > 0) {
obj.children = {
...obj
}
}
obj.value = value
return obj
}, {})
return res
}
const str = '[abc[bcd[def]]]'
console.log(normalize(str))
function parse(str) {
let s = str
const tokens = [
/^\[/,
/^\w+/,
/^\]/
]
let res = {}
let point = undefined
let parentMap = new Map()
while (s) {
for (let i = 0, l = tokens.length; i < l; i++) {
let token = s.match(tokens[i])
if (token) {
s = s.replace(tokens[i], '')
switch (i) {
case 0:
if (!point) {
point = res
parentMap.set(point, undefined)
} else {
point.children = {}
parentMap.set(point.children, point)
point = point.children
}
break
case 1:
point.value = token[0]
break
case 2:
point = parentMap.get(point)
break
}
}
}
}
return res
}
const normalize = (str = '') => {
const result = {};
const array = str.split(/[\[\]]/g).filter(Boolean);
const { length } = array;
array.reduce((previousValue, currentValue, currentIndex) => {
previousValue.value = currentValue;
if(currentIndex !== length - 1) return (previousValue.children = {})
}, result);
return result;
}
/**
*
* @param {string} str
*/
const Normalize = (str) => {
const obj = Object.create(null);
const arr = str.match(/\w+/g); //[ 'abc', 'bcd', 'def' ]
let index = 0;
(function createObj(obj) {
obj.value = arr[index++];
if (index === arr.length) return;
obj.children = {};
return createObj(obj.children);
})(obj);
console.log(JSON.stringify(obj, undefined, ' '));
return obj;
};
const Normalize = (str) => {
const arr = str.match(/\w+/g); //[ 'abc', 'bcd', 'def' ]
const obj = Object.create(null);
arr.reduce((pre, current, index) => {
pre['value'] = current;
if (index == arr.length - 1) return null;
pre['children'] = {};
return pre['children'];
}, obj);
return obj;
};
console.log(Normalize('[abc[bcd[def]]]'));
function normalize(str) {
const list = str.split(/[\[\]]/).filter(Boolean); // ['abc','bcd','def']
const res = {};
let temp = {};
for (let i = 0; i < list.length; i++) {
const item = list[i];
if (i === 0) {
res.value = item;
temp = res;
} else {
temp.children = {
value: item
};
temp = temp.children;
}
}
return res;
}
let arr = '[abc[bcd[def[hij]]]]'.match(/\w+/g)
//['abc', 'bcd', 'def']
let obj = {};
let res = {
val: arr.pop()
};
while (arr.length > 0) {
res = {
val: arr.pop(),
child: res
};
}
const normalize = (v) => {
if (v[0] != '[') return { value: v };
const jsonStr = v.replace(/\[([^\[\]]+)/g, (_, value) => (`"value": "${value}","children":{`))
.replaceAll(']', '}')
.replace(',"children":{}', '');
return JSON.parse(`{${jsonStr}}`);
};
const normalize = (str) => {
const root = {};
const holdMap = [];
let hold = root;
let floor = 0;
let subVal = '';
const setVal = () => {
if (!subVal) return;
hold.value = subVal;
subVal = '';
};
for (var c of str) {
if (c === '[') {
setVal();
holdMap[++floor] = hold;
hold.children = {};
hold = hold.children;
} else if (c === ']') {
setVal();
hold = holdMap[--floor];
} else {
subVal += c;
}
}
setVal();
return root.value ? root : (root.children || {});
};
const normalize2 = (str) => {
let arr = str.split(/[\[\]]/g).filter(Boolean)
let len = arr.length - 1
var result = {}
//递归的形式
let fun = (index, obj) => {
for (let i = index; i < arr.length; i++) {
obj.value = arr[index]
if (i !== len) {
obj.children = {}
fun(index + 1, obj.children)
}
}
}
fun(0, result)
}
function normalize(str) {
let temp = []
let valStart = false
let nowVal = ''
let obj = {}
let resKey = ''
for (let i = 0; i < str.length; i++) {
if (str[i] == '[') {
valStart = true
if (nowVal !== '') {
obj[nowVal] = {value: nowVal}
if (temp.length > 0) {
if (!obj[temp[temp.length - 1]].children) {
obj[temp[temp.length - 1]].children = []
}
obj[temp[temp.length - 1]].children.push(obj[nowVal])
}
temp.push(nowVal)
}
nowVal = ''
} else if (str[i] == ']') {
valStart = false
if (nowVal !== '') {
obj[nowVal] = {value: nowVal}
if (temp.length > 0) {
if (!obj[temp[temp.length - 1]].children) {
obj[temp[temp.length - 1]].children = []
}
obj[temp[temp.length - 1]].children.push(obj[nowVal])
}
temp.push(nowVal)
}
if (temp.length == 1) {
resKey = temp[0]
}
temp.pop()
nowVal = ''
} else if (valStart) {
nowVal += str[i]
}
}
return obj[resKey]
}
看起来大部分题解都只能支持逐级的链式结构,以数组方式处理字符串必然会丢失数据的结构化。这样处理数据导致重要参数丢失显然是不够健壮
let str = '[abc[xx[yy][zz]][cc[dd]]]'
console.log(str)
console.log(normalize(str))
可以以栈的方式存储上一级对象名称并根据对象的堆特性,来实现将字符串处理为简单对象的能力。
function nomalize(str) {
const props = str.match(/\w+/g);
if (props.length === 1) {
return { value: props[0] };
}
return props.reduceRight((children, parent) => {
if (typeof children === 'string') {
children = { value: children };
}
return { value: parent, children };
});
}
console.log(JSON.stringify(nomalize('abc')));
console.log(JSON.stringify(nomalize('[abc[bcd[def]]]')));