0

I have two list of objects:

list1 = [{value: 'X'}, {value: 'Y'}, ..., {value: 'Z'}];
list2 = [{value: 'A'}, {value: 'B'}, ..., {value: 'C'}];

I have this code that checks whether the values in list2 are in list1. If it is the code doesn't do anything, if not it should add to list1 (this will create a new list, list3). Which means I'm doing a union between the two list without keeping the repeated values.

for (let i = list2.length-1; i >= 0; i--) {
  let item = list2[i];
  let shared = false;
  for (let j = list1.length-1; j >=0; j--) {
    let childItem = list1[j];
    if (item.value === childItem.value) {
      shared = true;
      break;
    }
  }
  if (!shared) { newValues.push(item); }
}
list3 = list1.concat(newValues);

This works fine, but I was wondering if I could improve this O(n*m).

I'm not sure if the lists are always sorted by default, but from what I've seen both (list1 and list2) are always sorted by value.

Example:

var list1 = [{value: 'bar'}, {value: 'baz'}, {value: 'foo'}, {value: 'foz'}];
var list2 = [{value: 'bar'}, {value: 'foo'}, {value: 'test'}, {value: 'testz'}];
var list3 = union(list1, list2);
list3 = [{value: 'bar'}, {value: 'baz'}, {value: 'foo'}, {value: 'foz'}, {value: 'test'}, {value: 'testz'}];
2
  • When you say "whether the values in list2 are in list1" do you mean, if any, or if all, values? Commented Oct 11, 2017 at 19:38
  • I will add one example to clarify Commented Oct 11, 2017 at 19:40

2 Answers 2

3

Create a set of the values of list1, and Filter list2 by the values in the set before concating it to list1:

var list1 = [{value: 'bar'}, {value: 'baz'}, {value: 'foo'}, {value: 'foz'}];
var list2 = [{value: 'bar'}, {value: 'foo'}, {value: 'test'}, {value: 'testz'}];

const union = (list1, list2) => list1.concat(
  list2.filter(function({ value }) { // filter list2
    return !this.has(value); // filter out items which value is in the set
  }, new Set(list1.map(({ value }) => value))) // the set of list1 values
);

const list3 = union(list1, list2);

console.log(list3);

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

3 Comments

The question was about improving the (worst case) complexity. How does your solution do in this regard and is it actually better in terms of asymptotic behavior?
So what is the improvement of your code compared to the one I posted? Is it because you don't create a temp list?
It's because I don't have a loop inside a loop, which gives you the O(n * m). Creating a Set is O(2n). Filtering list2 is O(m). Concating is O(n + m). So the overall complexity is O(3n + 2m), and we can remove the constants for O(n + m).
2

You could use a single loop and store the value in a set for later check. Complexity: O(n).

var list1 = [{ value: 'X' }, { value: 'Y' }, { value: 'C' }, { value: 'Z' }],
    list2 = [{ value: 'A' }, { value: 'B' }, { value: 'C' }, { value: 'D' }],
    list3 = list1
        .concat(list2)
        .filter((s => ({ value }) => !s.has(value) && s.add(value))(new Set));

console.log(list3);
.as-console-wrapper { max-height: 100% !important; top: 0; }

2 Comments

Actually O(n + m) because you iterate list1 + list2
@OriDrori, for linear complexity, O(n) is sufficient to describe it.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.