![](/img/trans.png)
[英]Sorting an array of objects based on relevance of a key-value pair (JavaScript)
[英]How can I separate similar or alike items in an array of objects based on a specific key-value pair for each item?
我得到了一组对象。 数组中的每个对象都有一个关键的 PlanType...我需要确保没有具有相同 PlanType 的对象彼此相邻...
即使有时无法完全分离类似的项目,我该如何实现这一点。
[{Item: 1,PlanType: A}, {Item: 2,PlanType: B}, {Item: 3,PlanType: C}, {Item: 4,PlanType: C}, {Item: 5,PlanType: A}, {Item: 6,PlanType: A}, {Item: 7,PlanType: B}, {Item: 8,PlanType: A}, {Item: 9,PlanType: C}, {Item: 10,PlanType: A}]
预期结果...
[{Item: 1,PlanType: A}, {Item: 2,PlanType: B}, {Item: 3,PlanType: C}, {Item: 5,PlanType: A}, {Item: 4,PlanType: C}, {Item: 6,PlanType: A}, {Item: 7,PlanType: B}, {Item: 8,PlanType: A}, {Item: 9,PlanType: C}, {Item: 10,PlanType: A}]
这是我试过的代码......
//Sort the array into an object of arrays by PlanType
let plan_types = {};
original_array.forEach(item => {
if(plan_types[item.plan_type] === undefined){
Object.assign(plan_types, {
[item.plan_types]: []
})
}
plan_types[item.plan_types].push(item);
});
//Loop through the list of Plan types and try to evenly space out the items across a new array of the same size
let new_array = new Array(original_array.length).fill(null);
Object.keys(program_types).forEach((item,index) => {
let new_array_index = 0;
let item_index = 0;
const frequency = Math.ceil(new_array.length / plan_types[item].length);
while(new_array_index < new_array.length){
if(new_array[new_array_index] !== null) new_array_index ++;
else{
new_array[new_array_index] = plan_types[item][item_index];
new_array_index += frequency;
item_index ++;
}
}
})
问题是你一直通过它,它错过了填充一些项目。 留下空点和项目被遗漏。
您可以这样做,这可能不是最有效的方法,但它可以帮助您解决问题。
let A='A', B='B', C='C', D='D';
let f = [{ Item: 1, PlanType: A }, { Item: 2, PlanType: B }, { Item: 3, PlanType: C }, { Item: 4, PlanType: C }, { Item: 5, PlanType: A }, { Item: 6, PlanType: A }, { Item: 7, PlanType: B }, { Item: 8, PlanType: A }, { Item: 9, PlanType: C }, { Item: 10, PlanType: A } ];
let prevItem=f[0];
let currentItem;
for(let i=1; i<f.length; i++){
currentItem = f[i];
if(currentItem.PlanType === prevItem.PlanType){
f.splice(i,1);
f.push(currentItem);
console.log("Item shifted");
};
prevItem = currentItem;
}
console.log(f);
我在解决算法方面很糟糕,但这就是我想出的。 它还处理具有相同键的多个对象的情况,一个接一个。
基本上我已经从一个数组中创建了另一个数组,我只是检查当前迭代中的项目是否与我的新数组中的相同。 如果是,请将其添加到“堆栈”中。 每当第一个条件失败时,它将继续将当前项插入到新数组中。 这样做之后,我只是检查是否可以从该堆栈中获取一个项目并将其插入到新数组中,并将其从重复项数组中删除。
const items = [
{ Item: 1, PlanType: 'A' },
{ Item: 2, PlanType: 'B' },
{ Item: 3, PlanType: 'C' },
{ Item: 4, PlanType: 'C' },
{ Item: 5, PlanType: 'C' },
{ Item: 6, PlanType: 'A' },
{ Item: 7, PlanType: 'A' },
{ Item: 8, PlanType: 'B' },
{ Item: 9, PlanType: 'A' },
{ Item: 10, PlanType: 'C' },
{ Item: 11, PlanType: 'A' }
];
function normalizeList(items) {
if (items.length < 1) return items;
const result = [];
const duplicateItems = [];
items.forEach((item, index) => {
if (result.length && item.PlanType === result[result.length - 1].PlanType) {
if(index === items.length - 1) result.push(item);
else duplicateItems.push(item);
}
else {
result.push(item);
if(duplicateItems.length && duplicateItems[0].PlanType !== item.PlanType) {
result.push(duplicateItems.shift());
}
}
});
return result;
}
在我看来,将价值相等(或子财产价值相等)的相邻物品可靠地相互远离,不能通过基本比较来完成。 将要提出的方法不能称为优雅,因为它在很大程度上基于直接数组变异和计数索引。 它旨在解决第一次迭代步骤中的任务,例如......
relocateEqualNeighboringItemValues(["A", "A", "B"]) => ["A", "B", "A"]
relocateEqualNeighboringItemValues(["A", "A", "B", "C", "C"]) => ["A", "C", "B", "A", "C"]
通过第二个迭代步骤,还可以传递一个getter
,例如,对于更复杂结构的项目,确实针对项目的特定属性......
relocateEqualNeighboringItemValues([
{ item: 1, planType: "A" },
{ item: 2, planType: "A" },
{ item: 3, planType: "B" }
], (item => item.planType)) => [
{ item: 1, planType: "A" },
{ item: 3, planType: "B" },
{ item: 2, planType: "A" }
]
实现看起来像这样......
function relocateEqualNeighboringItemValues(arr, getItemValue) {
if (Array.isArray(arr) && (arr.length >= 3)) {
const getValue = ((
(typeof getItemValue === 'function') &&
(item => (item && getItemValue(item)))
) || (item => item)); // getter default.
let isTerminateRelocation = false;
let isRelocateItem;
let offsetCount;
let itemCount;
let itemValue;
let leftToRightIndex;
let rightToLeftIndex = arr.length;
while (!isTerminateRelocation && (--rightToLeftIndex >= 0)) {
isRelocateItem = false;
itemValue = getValue(arr[rightToLeftIndex]);
// - Exercise repeatedly from right to left for each item a relocation lookup,
// and, if possible, try to relocated such an equal neighboring item (value).
if (itemValue === getValue(arr[rightToLeftIndex - 1])) {
offsetCount = 1;
isRelocateItem = true;
while (isRelocateItem && ((rightToLeftIndex - (++offsetCount)) >= 0)) {
if (
(itemValue !== getValue(arr[rightToLeftIndex - offsetCount])) &&
(itemValue !== getValue(arr[rightToLeftIndex - offsetCount - 1]))
) {
arr.splice((rightToLeftIndex - offsetCount), 0, arr.splice(rightToLeftIndex, 1)[0]);
++rightToLeftIndex; // reset ... start look-up from the former entering position.
isRelocateItem = false;
}
}
// - In case the right to left relocation for a specific item got stuck (reached array boundaries),
// change lookup direction exclusively for this item from left to right and try relocating it.
// - Does the relocation attempt fail yet again, nothing can be done. The process will terminate.
if (isRelocateItem && ((rightToLeftIndex - offsetCount) < 0)) {
offsetCount = 1;
itemCount = arr.length;
leftToRightIndex = Math.max(0, (rightToLeftIndex - 1));
itemValue = getValue(arr[leftToRightIndex]);
isRelocateItem = (itemValue === getValue(arr[leftToRightIndex + 1]));
while (isRelocateItem && ((leftToRightIndex + (++offsetCount)) < itemCount)) {
if (
(itemValue !== getValue(arr[leftToRightIndex + offsetCount])) &&
(itemValue !== getValue(arr[leftToRightIndex + offsetCount + 1]))
) {
arr.splice((leftToRightIndex + offsetCount), 0, arr.splice(leftToRightIndex, 1)[0]);
isRelocateItem = false;
}
}
if (isRelocateItem && ((leftToRightIndex + offsetCount) >= itemCount)) {
isTerminateRelocation = true;
}
}
}
}
}
return arr;
}
测试用例
基本的
function relocateEqualNeighboringItemValues(a,b){if(Array.isArray(a)&&3<=a.length){const c="function"==typeof b&&(a=>a&&b(a))||(a=>a);let d,e,f,g,h,i=!1,j=a.length;for(;!i&&0<=--j;)if(d=!1,g=c(a[j]),g===c(a[j-1])){for(e=1,d=!0;d&&0<=j-++e;)g!==c(a[je])&&g!==c(a[je-1])&&(a.splice(je,0,a.splice(j,1)[0]),++j,d=!1);if(d&&0>je){for(e=1,f=a.length,h=Math.max(0,j-1),g=c(a[h]),d=g===c(a[h+1]);d&&h+ ++e<f;)g!==c(a[h+e])&&g!==c(a[h+e+1])&&(a.splice(h+e,0,a.splice(h,1)[0]),d=!1);d&&h+e>=f&&(i=!0)}}}return a} console.log('["A", "A", "B"] => ', relocateEqualNeighboringItemValues(["A", "A", "B"])); console.log('["A", "B", "B"] => ', relocateEqualNeighboringItemValues(["A", "B", "B"])); console.log('["A", "A", "B", "C", "C"] => ', relocateEqualNeighboringItemValues(["A", "A", "B", "C", "C"])); console.log('["A", "A", "C", "B", "C", "C"] => ', relocateEqualNeighboringItemValues(["A", "A", "C", "B", "C", "C"])); console.log('["A", "A", "C", "C", "B", "C", "C"] => ', relocateEqualNeighboringItemValues(["A", "A", "C", "C", "B", "C", "C"]));
.as-console-wrapper { max-height: 100%!important; top: 0; }
复杂,具有 getter 功能但可解析
function relocateEqualNeighboringItemValues(a,b){if(Array.isArray(a)&&3<=a.length){const c="function"==typeof b&&(a=>a&&b(a))||(a=>a);let d,e,f,g,h,i=!1,j=a.length;for(;!i&&0<=--j;)if(d=!1,g=c(a[j]),g===c(a[j-1])){for(e=1,d=!0;d&&0<=j-++e;)g!==c(a[je])&&g!==c(a[je-1])&&(a.splice(je,0,a.splice(j,1)[0]),++j,d=!1);if(d&&0>je){for(e=1,f=a.length,h=Math.max(0,j-1),g=c(a[h]),d=g===c(a[h+1]);d&&h+ ++e<f;)g!==c(a[h+e])&&g!==c(a[h+e+1])&&(a.splice(h+e,0,a.splice(h,1)[0]),d=!1);d&&h+e>=f&&(i=!0)}}}return a} const items = [ { Item: 0, PlanType: 'B' }, { Item: 1, PlanType: 'B' }, { Item: 2, PlanType: 'A' }, { Item: 3, PlanType: 'C' }, { Item: 4, PlanType: 'C' }, { Item: 5, PlanType: 'C' }, { Item: 6, PlanType: 'A' }, { Item: 7, PlanType: 'A' }, { Item: 8, PlanType: 'B' }, { Item: 9, PlanType: 'A' }, { Item: 10, PlanType: 'A' }, { Item: 11, PlanType: 'A' }, { Item: 12, PlanType: 'A' } // { Item: 13, PlanType: 'A' } ]; console.log(items, ' => ', relocateEqualNeighboringItemValues(Array.from(items).reverse(), (item => item.PlanType)).reverse()); console.log(items, ' => ', relocateEqualNeighboringItemValues(Array.from(items).reverse(), (item => item.PlanType))); console.log(items, ' => ', relocateEqualNeighboringItemValues(Array.from(items), (item => item.PlanType)).reverse()); console.log(items, ' => ', relocateEqualNeighboringItemValues(Array.from(items), (item => item.PlanType)));
.as-console-wrapper { max-height: 100%!important; top: 0; }
复杂,具有 getter 函数但不再可解析
function relocateEqualNeighboringItemValues(a,b){if(Array.isArray(a)&&3<=a.length){const c="function"==typeof b&&(a=>a&&b(a))||(a=>a);let d,e,f,g,h,i=!1,j=a.length;for(;!i&&0<=--j;)if(d=!1,g=c(a[j]),g===c(a[j-1])){for(e=1,d=!0;d&&0<=j-++e;)g!==c(a[je])&&g!==c(a[je-1])&&(a.splice(je,0,a.splice(j,1)[0]),++j,d=!1);if(d&&0>je){for(e=1,f=a.length,h=Math.max(0,j-1),g=c(a[h]),d=g===c(a[h+1]);d&&h+ ++e<f;)g!==c(a[h+e])&&g!==c(a[h+e+1])&&(a.splice(h+e,0,a.splice(h,1)[0]),d=!1);d&&h+e>=f&&(i=!0)}}}return a} const items = [ { Item: 0, PlanType: 'B' }, { Item: 1, PlanType: 'B' }, { Item: 2, PlanType: 'A' }, { Item: 3, PlanType: 'C' }, { Item: 4, PlanType: 'C' }, { Item: 5, PlanType: 'C' }, { Item: 6, PlanType: 'A' }, { Item: 7, PlanType: 'A' }, { Item: 8, PlanType: 'B' }, { Item: 9, PlanType: 'A' }, { Item: 10, PlanType: 'A' }, { Item: 11, PlanType: 'A' }, { Item: 12, PlanType: 'A' }, { Item: 13, PlanType: 'A' } ]; console.log(items, ' => ', relocateEqualNeighboringItemValues(Array.from(items), (item => item.PlanType)));
.as-console-wrapper { max-height: 100%!important; top: 0; }
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.