Remove duplicated combination in array based on index

Viewed 138

I have the following data array:

const data = [
  {
    value: [
      'a',
      'b',
      'a',
      'a'
    ]
  },
  {
    value: [
      'c',
      'c',
      'd',
      'c'
    ]
  }
];

So there's is 4 combination here based on index:
combination 1 : a - c (index 0 in each value arrays)
combination 2 : b - c (index 1 in each value arrays)
combination 3 : a - d (index 2 in each value arrays)
combination 4 : a - c (index 3 in each value arrays)

As you can see the first and the last combinations are the same, so i want to remove the second occurrence from each array, the result should be:

    [
        {
        value: [
          'a',
          'b',
          'a'
        ]
      },
      {
        value: [
          'c',
          'c',
          'd'
        ]
      }
  ]
4 Answers

You can zip the values arrays from both objects to form an array which looks like:

["a-c", "b-c", ...]

As these are now strings, you can turn this array into a Set using new Set(), which will remove all duplicate occurrences. You can then turn this set back into an array which you can then use .reduce() on to build you array of objects from. For each value you can obtain the list of values by using .split() on the '-', and from that, populate your reduced array.

See example below:

const data = [{ value: [ 'a', 'b', 'a', 'a' ] }, { value: [ 'c', 'c', 'd', 'c' ] } ];

const unq = [...new Set(
  data[0].value.map((_,c)=> data.map(({value})=>value[c]).join('-')) 
)];
const res = unq.reduce((acc, str) => {
  const values = str.split('-');
  values.forEach((value, i) => acc[i].value.push(value));
  return acc;
}, Array.from({length: data.length}, _ => ({value: []})))
console.log(res);

Limitations of the above method assume that you won't have a - character as your string value. If this is an issue, you can consider using a different delimiter, or find unique values within your array using .filter() instead of a Set.

You could save a lookup object for unique pairs of value based with index

Given your input is, below solution could help you

const data = [
  {
    value: ["a", "b", "a", "a"],
  },
  {
    value: ["c", "c", "d", "c"],
  },
]

const lookup = {}

data[0].value.forEach((_, index) => {
  lookup[`${data[0].value[index]}-${data[1].value[index]}`] = true
})

const res = Object.keys(lookup).reduce(
  (acc, key) => {
    const [val1, val2] = key.split("-")
    acc[0].value.push(val1)
    acc[1].value.push(val2)
    return acc
  },
  [{ value: [] }, { value: [] }]
)

console.log(res)

Below is a two step solution with a generator function and a single pass.

const data = [ { value: [ 'a', 'b', 'a', 'a' ] }, { value: [ 'c', 'c', 'd', 'c', ] } ];

const zipDataValues = function* (data) {
  const iterators = data.map(item => item.value[Symbol.iterator]())
  let iterations = iterators.map(iter => iter.next())
  while (iterations.some(iteration => !iteration.done)) {
    yield iterations.map(iteration => iteration.value)
    iterations = iterators.map(iter => iter.next())
  }
}

const filterOutDuplicateCombos = function (values) {
  const combosSet = new Set(),
    resultData = [{ value: [] }, { value: [] }]
  for (const [valueA, valueB] of values) {
    const setKey = [valueA, valueB].join('')
    if (combosSet.has(setKey)) {
      continue
    }
    combosSet.add(setKey)
    resultData[0].value.push(valueA)
    resultData[1].value.push(valueB)
  }
  return resultData
}

console.log(
  filterOutDuplicateCombos(zipDataValues(data))
) // [ { value: [ 'a', 'b', 'a' ] }, { value: [ 'c', 'c', 'd' ] } ]

Here is a reference on generators and iterators

Filter combinations + sorting by the first occurrence:

const data = [{
  value: ['a', 'b', 'a', 'a']
},{
  value: ['c', 'c', 'd', 'c']
}];

var res = {}, i, t;

for (i = 0; i < data[0].value.length; ++i) {
  res[data[0].value[i]] = res[data[0].value[i]] || {};
  res[data[0].value[i]][data[1].value[i]] = true;
}

data[0].value = [];
data[1].value = [];

for (i in res) {
  for (t in res[i]) {
    data[0].value[data[0].value.length] = i;  
    data[1].value[data[1].value.length] = t;  
  }
}

console.log(data);

Related