5

We have an array of arrays like this:

const arrays = [
  [0, 1, 2, 3, 4, 4, 4, 4],
  [5, 6, 7, 8, 9, 10, 11, 11],
  [2, 7, 10, 12],
  [0, 7, 10, 14]
]; 

There may be duplicate elements in each array and that's fine.

But I'm after a proper solution to remove duplicate elements in each set comparing to lower sets!

So as we have a 0 in the first array and the last array, we should consider the 0 in last one a duplication and remove it...

the desired result would be:

[0, 1, 2, 3, 4, 4, 4, 4],
[5, 6, 7, 8, 9, 10, 11, 11],
[12],
[14]

It's a confusing issue for me please help...

2
  • 5
    why do you keep 10 in third array? have you tried anything? Commented Oct 2, 2020 at 15:25
  • That was a mistake after a whole day trying to learn Javascript :) Commented Oct 2, 2020 at 15:26

6 Answers 6

6

You could collect the values in an object with index as value, and filter for values who are at the same index.

const
    arrays = [[0, 1, 2, 3, 4, 4, 4, 4], [5, 6, 7, 8, 9, 10, 11, 11], [2, 7, 10, 12], [0, 7, 10, 14]], 
    seen = {},
    result = arrays.map((array, i) => array.filter(v => (seen[v] ??= i) === i));

result.forEach(a => console.log(...a));

Sign up to request clarification or add additional context in comments.

3 Comments

it is a logical nullish assignment ??=, where the value is assigned, if the lhs is null or undefined.
@Pixier Nina is a JavaScript compiler.
modern JS has a lot of syntax that you won't find explained in older tutorials, so depending on how old your book/tutorials are you might be missing out. Have a look at freecodecamp.org/news/javascript-new-features-es2020, blog.logrocket.com/5-es2019-features-you-can-use-today, and look for some more "new features in ES1234" for each year since your book/tutorial got published. Super worth it.
0

const arrays = [
  [0, 1, 2, 3, 4, 4, 4, 4],
  [4, 4, 5, 6, 7, 8, 9, 10, 11, 11],
  [2, 7, 10, 12],
  [0, 7, 10, 14]
]

let filtered = arrays.map((row, i) => {
  // concat all previous arrays
  let prev = [].concat(...arrays.slice(0, i))
  // filter out duplicates from prev arrays
  return row.filter(r => !prev.includes(r))
})

console.log(filtered)

4 Comments

note that this has a very high runtime order. building an index lookup would be quite a bit faster, at a cost of an insignificant amount of additional memory.
@Mike'Pomax'Kamermans, I agree, for arrays of more than trivial size, you should build an index variable
I'd go so far as to say "using the algorithm with the lower runtime complexity is always the better choice", even for the data shown in the question.
Simplified down to: arrays.map((r,i)=>(p =>r.filter(v=>!p.includes(v)))([].concat(...arrays.slice(0, i))))
0

We can do this using Array#reduce and maintain a seen Set, which will have all visited numbers from each array.

Once you iterate over an array you push all visited elements in the seen Set, then push a new array filtered by the elements not in the seen Set:

const arrays = [
  [0, 1, 2, 3, 4, 4, 4, 4],
  [5, 6, 7, 8, 9, 10, 11, 11],
  [2, 7, 10, 12],
  [0, 7, 10, 14]
]; 

const removeDupsInSibling = (arr) => {
  let seen = new Set();
  return arr.reduce((acc, a)=> {
    const f = a.filter(v => !seen.has(v));
    seen = new Set([...seen, ...a]);
    acc.push(f);
    return acc;
  }, []);
}

console.log(removeDupsInSibling(arrays));

Comments

0

There are plenty of inefficient ways to do this, but if you want to do this in O(n), then we can make the observation that what we want to know is "which array a number is in". If we know that, we can run our algorithm in O(n):

for every element e in array at index i:
  if index(e) == i:
    this is fine
  if index(e) < i:
    remove this e

So let's just do literally that: we allocate an object to act as our lookup, and then we run through all elements:

const lookup = {};

const arrays = [
  [0, 1, 2, 3, 4, 4, 4, 4],
  [5, 6, 7, 8, 9, 10, 11, 11],
  [2, 7, 10, 12],
  [0, 7, 10, 14]
];

const reduced = arrays.map((array, index) => {
  // run through the elements in reverse, so that we can
  // safely remove bad elements without affecting the loop:
  for(let i=array.length-1; i>=0; i--) {
    let value = array[i];
    let knownIndex = (lookup[value] ??= index);
    if (knownIndex < index) {
      // removing from "somewhere" in the array
      // uses the splice function:
      array.splice(i,1);
    }
  }
  return array;
});

console.log(reduced);

For an alternative, where the loop+splice is taken care of using filter, see Nina's answer.

Comments

0

Simple, clean and high performance solution:

const arrays = [
  [0, 1, 2, 3, 4, 4, 4, 4],
  [5, 6, 7, 8, 9, 10, 11, 11],
  [2, 7, 10, 12],
  [0, 7, 10, 14]
]; 

const duplicates = {};

const answer = arrays.map( (array, level) => {
  return array.filter( el => {
    if ( duplicates[el] < level ) {
      // return nothing; fine
    } else {
      duplicates[el] = level;
      return el
    }
  })
});

console.log(JSON.stringify(answer))

here is on-liner and less-readable form:

const d = {}, arrays = [ [0, 1, 2, 3, 4, 4, 4, 4], [5, 6, 7, 8, 9, 10, 11, 11], [2, 7, 10, 12], [0, 7, 10, 14]];

const answer = arrays.map((a,l)=> a.filter(el=> d[el]<l ? 0 : (d[el]=l,el)));

console.log(JSON.stringify(answer))

2 Comments

Check the desired output.
This answer deserved more recognition; readability and performance wise.
-1
const arrays = [
  [0, 1, 2, 3, 4, 4, 4, 4],
  [5, 6, 7, 8, 9, 10, 11, 11],
  [2, 7, 10, 12],
  [0, 7, 10, 14],
];

const output = arrays.reduce(
  ({ output, set }, current, i) => {
    output[i] = current.filter((num) => !set.has(num));
    [...new Set(output[i])].forEach((num) => set.add(num));
    return { output, set };
  },
  { output: [], set: new Set() }
).output;

console.log(output);

Gets the exact output you want:

[
  [
    0, 1, 2, 3,
    4, 4, 4, 4
  ],
  [
    5,  6,  7,  8,
    9, 10, 11, 11
  ],
  [ 12 ],
  [ 14 ]
]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.