Как можно разделить похожие или похожие элементы в массиве объектов на основе определенной пары ключ-значение c для каждого элемента? - PullRequest
0 голосов
/ 21 марта 2020

Мне дали массив объектов. Каждый объект в массиве имеет ключ 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 ++;
    }
  }
})

Проблема в том, что вы проходите через все это, и вам не хватает заполнения некоторых Предметы. Оставляя пустые места и предметы не учитываются.

Ответы [ 3 ]

0 голосов
/ 22 марта 2020

Я ужасно разбираюсь в алгоритмах, но это то, что я придумал. Это также относится к случаю, когда у вас есть несколько объектов с одним и тем же ключом, один за другим.

В основном я создал другой массив из предоставленного, я просто проверяю, является ли элемент текущей итерации так же, как из моего нового массива. Если это так, добавьте его в «стек». Всякий раз, когда первое условие не выполняется, он продолжает вставлять текущий элемент в новый массив. После этого я просто проверяю, могу ли я получить элемент из этого стека и вставить его в новый массив, удалив его из массива duplicateItems.

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;
}
0 голосов
/ 24 марта 2020

Надежное смещение соседних предметов равной ценности (или равной стоимости дочернего имущества) друг от друга, на мой взгляд, не может быть выполнено путем базового 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; }
0 голосов
/ 21 марта 2020

Вы можете сделать это, возможно, не самым эффективным способом, но это может помочь вам решить вашу проблему.

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);

Пример кода

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...