0
\$\begingroup\$

As the question already says, my code returns a list with the index's that don't exist inside another list.

For this I currently create two lists joining the objects of each index, then filter the values not found and finally I do a loop searching in which index I will find this value within the initial list:

function notfind() {
  const history = [['a','b'],['c','d']]
  const history_join = [];
  var i=0;
  var max = history.length;
  for(i; i<max; i++){
    history_join.push(history[i][0] + history[i][1]);
  }
  
  const new_values = [['c','d'],['e','f']]
  const new_values_join = [];
  var i=0;
  var max = new_values.length;
  for(i; i<max; i++){
    new_values_join.push([new_values[i][0] + new_values[i][1]]);
  }

  const not_match = new_values_join.filter(x => !history_join.includes(x[0]));
  
  var not_contains = [];
  var i=0;
  var max = new_values_join.length;
  for(i; i<max; i++) {
    if (not_match.includes(new_values_join[i])) {
      not_contains.push(new_values[i])
    }
  }
  console.log(not_contains);
}

Output:

[['e','f']]

I would like a review of the method to improve the execution time and number of tasks until reaching the desired result.


Additional information of a method security flaw found by @DaveMeehan:

What if history was [‘a’,’b’] and new values was [‘ab’,’’]

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Is concatenating the two values reliable? What if history was [‘a’,’b’] and new values was [‘ab’,’’]? Why is it necessary to concatenating when comparing the elements of history and new would appear to suffice? \$\endgroup\$ Commented Jun 28, 2022 at 7:08
  • \$\begingroup\$ Hi @DaveMeehan , I really hadn't thought of that, it's a serious security issue. \$\endgroup\$ Commented Jun 28, 2022 at 11:11

3 Answers 3

3
\$\begingroup\$

Your solution can be simplified to a few lines.


This peice of code is written twice in your function and simply creates a list of "keys" to identify each sub array of your list.

for(i; i<max; i++){
  history_join.push(history[i][0] + history[i][1]);
}

You could create a function that handles building the key and call it whenever you want.

const buildKey = arr => arr.join('');

The advantage of that is, you won't be limitted to two items of your sub array.


You're also playing around with multiple lists within your function but that seems to overly complicate your end goal.

You should instead:

  1. Build keys from your history list and store efficient Set object.
  2. Build keys from your new_values list and see if it exists in the Set object.
  3. If the new_value key doesn't exist in Set well you can filter it out.

Full solution:

const buildKey = arr => arr.join(':');

const notFound = (input, history) => {
  const historySet = new Set(history.map(buildKey));
  return input.filter((arr) => !historySet.has(buildKey(arr)))
}

const history = [['a','b'],['c','d']];
const input = [['c','d'],['e','f'], ['ab', '']];

const result = notFound(input, history);

console.log(result)

\$\endgroup\$
2
  • \$\begingroup\$ Hi @kemicofaghost , Dave Meehan brought a very important security point that I hadn't noticed and that your option also fell into the same trap, if there is a new value [‘ab’,’’], it doesn't appear as a result list because if join values, ab will continue to be ab. \$\endgroup\$ Commented Jun 28, 2022 at 11:09
  • \$\begingroup\$ @DigitalFarmer then just do join(':') when building the key. \$\endgroup\$
    – kockburn
    Commented Jun 28, 2022 at 12:13
1
\$\begingroup\$

The reason why I asked about concatenation is that its unnecessary unless you wanted to catch matching concatenations regardless of the inputs. It seems that's not the case, so why not just compare elements?

const notFound = (input, history) => {
    return input.filter(inItem => {
        return !history.find(histItem => {
            return inItem.length === histItem.length && inItem.reduce((acc, cur, index) => cur === histItem[index], true)
        })
    })
}

const history = [['a','b'],['c','d']];
const input = [['c','d'],['e','f'], ['ab', '']];

const result = notFound(input, history);

console.log(result)
\$\endgroup\$
0
\$\begingroup\$

After @DaveMeehan's comment:

Is concatenating the two values reliable? What if history was [‘a’,’b’] and new values was [‘ab’,’’]? Why is it necessary to concatenating when comparing the elements of history and new would appear to suffice?

I noticed the severe problem encountered in concatenating the values, so an option to fix the problem was:

const history = [['a','b'],['c','d']];
const new_values = [['c','d'],['ab',''],['e','f']];

const result = [];
for (var key of new_values) {
  if (!JSON.stringify(history).includes(JSON.stringify(key))) {
    result.push(key)
  }
}
console.log(result)

\$\endgroup\$

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.