我想减少这个嵌套数组:
const list = ['Map<%s,%s>', ['string', 'Map<%s,%s>', ['string', 'boolean']]];
该列表将变为:
'Map<string,Map<string,boolean>>'
这是一个开始,但是回想起来确实让我感到困惑:
const util = require('util');
const reduceToString = function(l){
return l.reduceRight((a,b) => {
if(Array.isArray(a)){
return reduceToString(a);
}
return util.format(b, a);
});
};
console.log(reduce(list));
为了更好地理解它是如何工作的,请输入以下内容:
const list = ['Map<%s,%s,%s>', ['string', 'Map<%s,%s>', ['string', 'boolean'], 'number']];
应产生:
'Map<string,Map<string,boolean>,number>'
一般规则是:字符串右边的任何数组都应内插到字符串中,reduceToString函数应始终返回字符串。
答案 0 :(得分:4)
一种方法可以是“减少”作为数组的任何元素(下降到最深的层次),然后在不断从堆栈中返回“下一个元素”是数组的任何元素时进行替换: / p>
const list = ['Map<%s,%s,%s>', ['string', 'Map<%s,%s>', ['string', 'boolean'], 'Number']];
function merge(list) {
function reduce(arr) {
arr = arr.map(e => Array.isArray(e) ? reduce(e) : e);
return arr
.map((e, i) => Array.isArray(arr[i + 1])
? arr[i + 1].reduce((a, c) => a.replace('%s', c), e)
: e)
.filter(e => !Array.isArray(e));
}
return reduce(list)[0];
}
console.log(merge(list));
答案 1 :(得分:3)
您可以使用replace()
进行递归操作:
const list = ['Map<%s,%s,%s>', ['string', 'Map<%s,%s>', ['string', 'boolean'], 'Number']];
function replaceMatch(arr, i=0){
let str = arr[0]
return str.replace(/%s/g, () => {
let next = arr[1]
if (Array.isArray(next[i+1])) {
i+=2
return replaceMatch(next.slice(i-2))
}
else return next[i++]
})
}
str = replaceMatch(list)
console.log(str)
这是一个更长的但可能更易于阅读的递归版本。它返回一个数组而不是字符串,以允许非映射最终出现在结果中(例如,第一个和最后一个元素。如果映射的插槽比数组值多,它将添加一个?
,并忽略多余的数组没有相应的%s
的值:
const list = ["Name", 'Map<%s,%s,%s>', ['string', 'Map<%s,%s,%s>', ['string', 'boolean'], 'Number'], 'Set<%s,%s>', ['val_1', 'val_2']];
function replaceArr(str, arr){ // helper function for replace
let i = 0
return str.replace(/\%s/g, () => arr[i++] || '?')
}
function replaceMatch(arr){
let res = []
for (let i = 0; i < arr.length ; i++){
if (Array.isArray(arr[i])) continue
res.push(Array.isArray(arr[i+1])
? replaceArr(arr[i], replaceMatch(arr[i+1]))
: arr[i]
)
}
return res
}
str = replaceMatch(list)
console.log(str)
答案 2 :(得分:2)
这比我想象的要难得多。该解决方案返回一个数组,并且比其他解决方案和OP最初要求的更为通用。由于它可以连续处理两个字符串。
const util = require('util');
const list = ['Array','Map<%s,%s, %s>', ['xxx','Map<%s,%s>', ['string', 'boolean'], 'number']];
const reduce = function(list){
return list.slice(1).reduce((a,b) => {
if(Array.isArray(b)){
const pop = a.pop();
const format = util.format(pop,...reduce(b));
return a.concat(format);
}
return (a.push(b), a); // comma operator
},
[list[0]]
);
};
console.log(reduce(list));
以上内容将产生:
[ 'Array', 'Map<xxx,Map<string,boolean>, number>' ]