1

i have arrays like the following ones:

files = [
       {name: 'Lorem', other: true},
       {name: 'Foo', other: true},
       {name: 'Bar', other: true}
      ];


files = [
       {name: 'Lorem', other: true},
       {name: 'Xxxxx', other: true}
      ];


files = [
       {name: 'Lorem', other: true},
       {name: 'Foo', other: true},
       {name: 'Epic', other: true},
       {name: 'Xxxxx', other: true}
      ];

I'm trying to get a merged array with unique elements with Underscore, but it doesn't work. Here is my code:

function getAllFiles(alldocs) {
  var all = [];

  _.each(alldocs, function(element) {
    all = _.union(all, element.files);
  });

  return all;
}

But i get an array with duplicate items.

3
  • 2
    see github.com/jashkenas/underscore/issues/2311 Commented Mar 4, 2016 at 8:47
  • 1
    You could probably use underscorejs.org/#uniq also with union Commented Mar 4, 2016 at 8:48
  • The solutions given below all check just for the 'name' property, but it's possibly you want to distinct over both 'name' and 'other' properties. Loop over the array and check both. If it's just the single value you want to check, you could do it with a map and reduce one-liner. Commented Mar 4, 2016 at 9:06

5 Answers 5

2

Using underscore you can do it like this:

files1 = [
       {name: 'Lorem', other: true},
       {name: 'Foo', other: true},
       {name: 'Bar', other: true}
      ];


files2 = [
       {name: 'Lorem', other: true},
       {name: 'Xxxxx', other: true}
      ];


files3 = [
       {name: 'Lorem', other: true},
       {name: 'Foo', other: true},
       {name: 'Epic', other: true},
       {name: 'Xxxxx', other: true}
      ];
//append all  json
all = _.union(files1,files2, files3);
//get unique by define function which returns name (deciding factor for unique)
all = _.uniq(all, function(d){return d.name});
console.log(all);//prints the unique elements

working code here

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

Comments

1

A solution in plain Javascrift a temporary object and Array#forEach()

var files1 = [{ name: 'Lorem', other: true }, { name: 'Foo', other: true }, { name: 'Bar', other: true }],
    files2 = [{ name: 'Lorem', other: true }, { name: 'Xxxxx', other: true }],
    result = function (array) {
        var o = {}, r = [];
        array.forEach(function (a) {
            if (!(a.name in o)) {
                o[a.name] = a;
                r.push(o[a.name]);
            }
        });
        return r;
    }(files1.concat(files2));

document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');

Comments

1

You need to apply uniq method after union call.

The problem is that uniq by default uses === operator to test array element equality. So if you have array of objects, each object will be compared by reference, not value, which is obviously undesired behaviour. This problem can be solved by supplying uniq with extra parameter - callback function (iteratee) which will convert array element to simply comparable value. In your case you can use JSON.stringify method which returns string representation of an object.

function getAllFiles(alldocs) {
    var union = _.union.apply(null, alldocs.map(function(v) {
        return v.files;
    }));
    return _.uniq(union, function(v) {
        return JSON.stringify(v);
    });
}
var alldocs = [
    {files: [
       {name: 'Lorem', other: true},
       {name: 'Foo', other: true},
       {name: 'Bar', other: true}
    ]},
    {files: [
       {name: 'Lorem', other: true},
       {name: 'Xxxxx', other: true}
    ]},
    {files: [
       {name: 'Lorem', other: true},
       {name: 'Foo', other: true},
       {name: 'Epic', other: true},
       {name: 'Xxxxx', other: true}
    ]}
];
var result = getAllFiles(alldocs);

Fiddle

Comments

0

Using lodash, you can use _.uniqBy

result = _.uniqBy(result, function (e) {
  return e.name;
});

https://jsfiddle.net/mw230kea/1/

Comments

0

It is because you are using an arrays of objects and underscore doesn't know which object attribute to use when comparing items(for example name,other), here is a clean solution:

   files =  _.chain(files).indexBy("name").values();

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.