21

Essentially, I want to implement the following:

var categories = [];
var products = // some array of product objects
products.map(function(value) {
   if(categories.indexOf(value.Category === -1)) categories.push(value.Category);
});

As result, categories array contains unique list of product categories.

I feel that there should be a better way to do it, but nothing comes to mind.

If there isn't then probably there is no point to use map() in the first place. I could do as simple as

var categories = [];
var products = // some array of product objects
for (var i = 0; i < products.length; i++) {
   if(categories.indexOf(products[i].Category === -1)) categories.push(products[i].Category);
}

UPDATE for those who insist it's a duplicate of "how to make an array unique" question. I saw that post, and for my situation I don't think it applies. I don't have an array of values that I need to make unique. I have an array of objects and I need to build an array of unique values. The difference might be subtle - but to get to the use case of that topic I would build a non-unique array and then make it unique. Seems even worse than my original solution

11
  • 1
    Possible duplicate of Unique values in an array Commented Dec 25, 2015 at 20:06
  • please add some sample data. Commented Dec 25, 2015 at 20:15
  • i'm with @NinaScholz Commented Dec 25, 2015 at 20:15
  • 1
    i think, you misuse map for simply iterating. the right method is forEach. Commented Dec 25, 2015 at 20:18
  • 1
    @Andy - the value of Bek's answer is pointing out that I can use reduce() to build an array; as opposed to generating a scalar. There were some edits in Bek's answer; so maybe the error was fixed - or maybe I got the idea and implemented it correctly. In any event, it works fine! Commented Dec 25, 2015 at 20:46

4 Answers 4

23

you can use reduce instead of map

var products = [{Category:'vegetable', price: 1}, {Category:'fruits', price: 2}];
var categories = products.reduce(function(sum, product) {
 if(sum.indexOf(product.Category) === -1){
  sum.push(product.Category);
 }
 return sum;
}, []);
Sign up to request clarification or add additional context in comments.

6 Comments

reduce will give me a single value (eg., sum). I need array of values (eg., Categories)
It is not a single value it is array where things getting accumulated
Wow! Haven't thought of using reduce in this manner! Marking as answer
it rewrites product. categories is not defined. the whole object is pushed. indexof does not work on objects.
my point was to show how reduce could be used not solving specific problem anyways fixed it
|
6

Update: A solution with Array.prototype.reduce()

var products = [{ Name: 'milk', price: 2.50, Category: 'groceries' }, { Name: 'shirt', price: 10, Category: 'clothing' }, { Name: 'apples', price: 5, Category: 'groceries' }],
    categories = products.reduce(function (r, a) {
        if (!~r.indexOf(a.Category)) {
            r.push(a.Category);
        }
        return r;
    }, []);

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

6 Comments

I don't think this will work - within filter categories is always an empty array, and comparison will always return true. Or am I misunderstanding?
please supply some example data, the it's more likely to see what you want.
@Felix this answer shows how to implement what question asking (filter values in functional style vs. imperative), but it is not what you actually need and duplicate Vankat found answers it perfectly.
Products = [{Name: 'milk', price: 2.50, Category: 'groceries'}, {Name: 'shirt', price: 10, Category: 'clothing'}, {Name: 'apples', price: 5, Category: 'groceries'}] Expected result: Categories = ['groceries', 'clothing']
@Felix, in future, perhaps don't think of it as a race. Bex might have answered first wrt reduce but the answer was very poor/not checked.
|
3

map all the values of the object categories out first, then use filter to dispose of the duplicates.

var products = [
  { category: 'A' },
  { category: 'B' },
  { category: 'A' },
  { category: 'D' }
];

var categories = products.map(function (e) {
  return e.category;
}).filter(function (e, i, a) {
  return a.indexOf(e) === i;
}); // [ "A", "B", "D" ]

DEMO

1 Comment

@NinaScholz, does it say somewhere that indexOf was to be avoided?
0

Follow the Below SO Answer:

How to get distinct values from an array of objects in JavaScript?

var flags = [], output = [], l = array.length, i;
for( i=0; i<l; i++) {
    if( flags[array[i].age]) continue;
    flags[array[i].age] = true;
    output.push(array[i].age);
}

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.