Надежное смещение соседних предметов равной ценности (или равной стоимости дочернего имущества) друг от друга, на мой взгляд, не может быть выполнено путем базового c сравнения. Подход, который будет представлен, нельзя назвать элегантным, поскольку он основан на прямой мутации массива и в значительной степени учитывает индексы. Он был построен для решения на первом этапе итерации таких задач, как ...
relocateEqualNeighboringItemValues(["A", "A", "B"]) => ["A", "B", "A"]
relocateEqualNeighboringItemValues(["A", "A", "B", "C", "C"]) => ["A", "C", "B", "A", "C"]
Со вторым этапом итерации можно также передать getter
, например, для элементов более сложной структуры, предназначенных для спецификация элемента c свойство ...
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;
}
Контрольные примеры
Basi c
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[j-e])&&g!==c(a[j-e-1])&&(a.splice(j-e,0,a.splice(j,1)[0]),++j,d=!1);if(d&&0>j-e){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; }
Сложный, с функцией получения, но разрешимый
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[j-e])&&g!==c(a[j-e-1])&&(a.splice(j-e,0,a.splice(j,1)[0]),++j,d=!1);if(d&&0>j-e){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; }
Сложный, с функцией получения, но больше не разрешается
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[j-e])&&g!==c(a[j-e-1])&&(a.splice(j-e,0,a.splice(j,1)[0]),++j,d=!1);if(d&&0>j-e){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; }