2

I've got some data like this:

const items = [
  { _id: '1', reference: ['abc'] },
  { _id: '2', reference: ['def'] },
  { _id: '3', reference: ['abc'] }
]

The length of items is always different.

Now I need to get all unique reference strings in a single array. So the result should be

['abc', 'def']

as 'abc' is a duplicate.

I tried to use a forEach() loop:

const references = []
items.forEach(i => {
  references.concat(i.reference)
})

console.log(references)

But references just gets an empty array result. Also with that I did not take care of duplicates...


I would like to use an ES6 pattern. With that I know I could use something like this:

const array1 = ['abc']
const array2 = ['def']
const array3 = Array.from(new Set(array1.concat(array2)))

But how can I do this using a loop to get every reference array of each item object - even if I do not know how many objects are in the item array?

3 Answers 3

2

If you wanna do a functional style (map-reduce), you can do it like this

const items = [
  { _id: '1', reference: ['abc'] },
  { _id: '2', reference: ['def'] },
  { _id: '3', reference: ['abc'] }
]

// extract references and put them into a single array
const references = 
  items
    .map(x => x.reference)
    .reduce((prev, cur) => prev.concat(cur))
    
// put them in a set to dedupe
const set = new Set(references)

console.log(references)
console.log([...set])

If you want to do fewer passes over the data, and also avoid the need for Set you could do.

const items = [
  { _id: '1', reference: ['abc'] },
  { _id: '2', reference: ['def'] },
  { _id: '3', reference: ['abc'] }
]

const result = Object.keys(items.reduce((obj, {reference}) => {
  for (const ref of reference) {
    obj[ref] = true
  }
  return obj;
}, {}))

console.log(result)

You can also trade expressiveness for performance with a fully imperative approach below.

const items = [
  { _id: '1', reference: ['abc'] },
  { _id: '2', reference: ['def'] },
  { _id: '3', reference: ['abc'] }
];

const occ = {};
const references = [];
for (let i = 0; i < items.length; ++i) {
  const refs = items[i].reference;
  for (let j = 0; j < refs.length; ++j) {
    const ref = refs[j];
    if (occ[ref] == null) {
      references.push(ref);
      occ[ref] = true;
    }
  }
}

console.log(references)
  

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

4 Comments

If you're going to use .reduce(), you may as well do the deduping there and then your unique references are Object.keys(references). You can skip the .map() and new Set() portion entirely, saving you 2 iterations through your dataset
@mhodges true. I was just thinking of the most straightforward/expressive solution, and the op mentioned they wanted to use Set so I did it that way. I can edit in that answer as well.
Well, the OP said they would like to use an "ES6 Pattern", which I don't think is a real requirement. I think that is the OP's attempt at a solution thinking that ES6 is "clearly more efficient than ES5". However, 1 pass through the array with .reduce() is more time and algorithmically efficient than 3 passes through the array. Your for loop solution addresses the issue of the inefficiency, but it's unnecessarily verbose - not to mention, not using any "ES6 Patterns"
@mhodges yeah I know. I updated it with what you suggested.
2

If you want to use Sets, you can use Set.add, and spread syntax:

const items = [
  { _id: '1', reference: ['abc'] },
  { _id: '2', reference: ['def'] },
  { _id: '3', reference: ['abc'] }
]

var references = new Set();
items.forEach(i => references.add(...i.reference))
console.log(Array.from(references))

2 Comments

You can simplify it even further with Array.from(new Set(items.map(item => item.reference[0])));
For this case, it seems so. But because reference is an array, I'm assuming that there might be multiple values in the future.
1

This is similar to other solutions here, but creates a reusable function:

const uniqRefs = 
  items => [...items.reduce((s, i) => s.add(...i.reference), new Set())]


const items = [{"_id": "1", "reference": ["abc"]}, {"_id": "2", "reference": ["def"]}, {"_id": "3", "reference": ["abc"]}]
console.log(uniqRefs(items))

Comments

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.