给出具有以下结构的对象数组(固定长度):
{type: 'A', value: 1}
或
{type: 'B', text: 'b'}
找到所有类型为“ A”的对象序列并返回其索引的最简单方法是什么?
一个例子: 对于以下数组:
[
{type: 'A', value: 1}, {type: 'A', value: 2}, {type: 'B', text: 'b1'},
{type: 'A', value: 11}, {type: 'A', value: 12}, {type: 'A', value: 13},
{type: 'B', text: 'b2'}, {type: 'A', value: 10}, {type: 'B', text: 'b3'}
]
输出应为以下数组:
[
{startIndex: 0, startValue: 1, length: 2},
{startIndex: 3, startValue: 11, length: 3},
{startIndex: 7, startValue: 10, length: 1},
]
我猜天真的实现将是使用forEach
进行迭代,并具有许多复杂的条件,但是有没有更简单的技术?
谢谢。
答案 0 :(得分:3)
您可以减少数组并更改值和类型以创建新组。
var array = [{ type: 'A', value: 1 }, { type: 'A', value: 2 }, { type: 'B', text: 'b1' }, { type: 'A', value: 11 }, { type: 'A', value: 12 }, { type: 'A', value: 13 }, { type: 'B', text: 'b2' }, { type: 'A', value: 10 }, { type: 'B', text: 'b3' }],
result = array.reduce((r, { type, value }, i, a) => {
var previous = a[i - 1] || {},
last = r[r.length - 1];
if (!isFinite(value) || type !== 'A') return r;
if (previous.type !== type) {
r.push({ startIndex: i, startValue: value, length: 1 });
return r;
}
if (value === a[last.startIndex].value + last.length) last.length++;
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
答案 1 :(得分:2)
您可以像这样使用reduce
。添加变量prev
来跟踪先前的type
是什么。如果当前的type
是您要查找的类型:如果上一项具有不同的type
,则添加一个对象。否则,只需增加length
属性
let input = [{type:'A',value:1},{type:'A',value:2},{type:'B',text:'b1'},{type:'A',value:11},{type:'A',value:12},{type:'A',value:13},{type:'B',text:'b2'},{type:'A',value:10},{type:'B',text:'b3'}],
prev;
const output = input.reduce((acc, { type, value }, i) => {
if (type === 'A') {
if (prev !== type) {
acc.push({ startIndex: i, startValue: value, length: 1 })
} else {
acc[acc.length - 1].length++
}
}
prev = type
return acc;
}, [])
console.log(output)
答案 2 :(得分:0)
只需使用forEach
循环。它易于阅读,并且不会使您的代码复杂化。
let arr = [
{type: 'A', value: 1}, {type: 'A', value: 2}, {type: 'B', text: 'b1'},
{type: 'A', value: 11}, {type: 'A', value: 12}, {type: 'A', value: 13},
{type: 'B', text: 'b2'}, {type: 'A', value: 10}, {type: 'B', text: 'b3'}
]
function findSequences(arr, character) {
let seq = []
let seqStarted = false;
let seqI = 0;
arr.forEach((el, i) => {
if (el.type == character) {
if (seqStarted == true) {
seq[seqI].length += 1;
} else {
seqStarted = true;
seq.push({
startIndex: i,
startValue: el.value,
length: 1
});
}
} else {
if (seqStarted) {
seqStarted = false;
seqI++;
}
}
})
return seq;
}
console.log(findSequences(arr, 'A'))
答案 3 :(得分:0)
我认为仅使用for
循环遍历数组并构造所需的答案就不会更简单。此外,此解决方案具有线性复杂度,因为您只需遍历数组一次。不确定为什么需要“许多复杂条件”。
对我来说,这样的事情似乎还可以:
const arr = [
{type: 'A', value: 1}, {type: 'A', value: 2}, {type: 'B', text: 'b1'},
{type: 'A', value: 11}, {type: 'A', value: 12}, {type: 'A', value: 13},
{type: 'B', text: 'b2'}, {type: 'A', value: 10}, {type: 'B', text: 'b3'}
];
const result = [];
for (let [index, el] of arr.entries()) {
if (el.type === 'A') {
// account for the first entry found
if (result.length === 0) {
result.push({startIndex: index, length: 1, startValue: el.value});
} else {
const lastSequence = result[result.length - 1];
// check if the we are in a sequence
if (lastSequence.startIndex + lastSequence.length === index) {
lastSequence.length += 1;
} else {
// if we are not in a sequence - create a new one
result.push({startIndex: index, length: 1, startValue: el.value});
}
}
}
}
console.log(result);
答案 4 :(得分:0)
For your specified array:
var arr =[
{type: 'A', value: 1}, {type: 'A', value: 2}, {type: 'B', text: 'b1'},
{type: 'A', value: 11}, {type: 'A', value: 12}, {type: 'A', value: 13},
{type: 'B', text: 'b2'}, {type: 'A', value: 10}, {type: 'B', text: 'b3'}
];
arr.reduce((result, current, index) => {
if(current.type == 'A'){
if(result.length == 0 || index - result[result.length - 1].length != result[result.length - 1]. startIndex){
result.push({startIndex: index, startValue: current.value, length: 1})
}
else{
result[result.length - 1].length++
}
}
return result;
}, [])
答案 5 :(得分:0)
您可以在forEach中使用类似这样的声明性方法,而不是在命令中强制使用:
const a = [
{type: 'A', value: 1}, {type: 'A', value: 2}, {type: 'B', text: 'b1'},
{type: 'A', value: 11}, {type: 'A', value: 12}, {type: 'A', value: 13},
{type: 'B', text: 'b2'}, {type: 'A', value: 10}, {type: 'B', text: 'b3'}
];
var filtered = a.map((v,i) => {
return v.type == 'A' ? {startIndex: i,startValue: v.value} : null
}).filter(x => x).reduce((acc,v) => {
if (acc.filter(x => x.startIndex + x.length == v.startIndex).length > 0){
acc[acc.length-1].length ++;
} else {
v.length = 1;
acc.push(v);
}
return acc;
},[]);
console.log(filtered);
答案 6 :(得分:0)
尽管这里已经有很多不错的答案,但我想我还是要添加一个,它解决了细分列表的更一般的情况。使用此代码,可以指定一个segmenter
函数,该函数比较两个项目并确定是否应该开始一个新的段。
有了这些细分后,获得所需的最终答案非常简单。
const data = [
{type: 'A', value: 1}, {type: 'A', value: 2}, {type: 'B', text: 'b1'},
{type: 'A', value: 11}, {type: 'A', value: 12}, {type: 'A', value: 13},
{type: 'B', text: 'b2'}, {type: 'A', value: 10}, {type: 'B', text: 'b3'}
]
const segmentBy = segmenter => items => {
const segmentReducer = (prev = [], curr) => {
let lastSegment = [];
let lastItem = null;
try {
lastSegment = prev[prev.length - 1];
lastItem = lastSegment[lastSegment.length - 1];
} catch (e) {
return [...prev, [curr]];
}
const requiresNewSegment = segmenter(lastItem, curr);
if (requiresNewSegment) {
return [...prev, [curr]];
}
return [...prev.slice(0, prev.length - 1), [...lastSegment, curr]];
};
return items.reduce(segmentReducer, []);
};
const addIndex = a => a.map((x, i) => ({...x, index: i}))
const segmentByType = segmentBy((a, b) => a.type !== b.type);
const segments = segmentByType(addIndex(data));
const result = segments
.map(segment => ({
startIndex: segment[0].index,
startValue: segment[0].value || null,
length: segment.length
}))
.filter(x => x.startValue !== null)
console.dir(result);