3

Take an imaginary array of sold items where we oddly enough only are interested in the item title and value:

let items = [
    { title: "Trumping the Horns", value: 5.95 },
    { title: "Rocking about", value: 20.00 },
    { title: "Trumping the Horns", value: 5.95 }
]

I know I can get an array with the unique values rather easily:

const uniqueSales = [...new Set(items.map(item => item.title))];

But lets for instance say I want to know how many of each item I have sold, or the accumulated value of them? So:

[
    { title: "Trumping the Horns", amount: 2 },
    { title: "Rocking about", amount: 1 }
]

Is it possible to map those as well, without having to do some crazy sorting and iterating over that array? Preferebly in a one-liner. The main reason for not doing it server side is that I have a fair amount of different manipulations of the same data, and it seems most correct to just send it once and let the client handle the manipulations and presentations of the data.

7 Answers 7

7

You could use Map and store the reference to the new inserted objects of the result array.

var items = [{ title: "Trumping the Horns", value: 5.95 }, { title: "Rocking about", value: 20.00 }, { title: "Trumping the Horns", value: 5.95 }],
    result = items.reduce(
        (map => (r, a) => (!map.has(a.title) && map.set(a.title, r[r.push({ title: a.title, amount: 0 }) - 1]), map.get(a.title).amount++, r))(new Map),
        []
    );

console.log(result)

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

1 Comment

Beautiful - tyvm.
3

In ES6, we can get returned unique items from a single line of code as below,

// with arrays
const dupArr = [1, 1, 2, 3, 1];
const uniArr = [...(new Set(dupArr))];
// [1, 2, 3]

// with objects on a key.
const dupObj = [{ id: 1, value: 'a' }, { id: 2, value: 'b' }, { id: 1, value: 'c' }];
const uniKeys = [...(new Set(dupObj.map(({ id }) => id)))];
// [ '1', '2' ]

Comments

2

let items = [{
    title: "Trumping the Horns",
    value: 5.95
  },
  {
    title: "Rocking about",
    value: 20.00
  },
  {
    title: "Trumping the Horns",
    value: 5.95
  }
];

console.log(items.reduce(function(countMap, item) {
  countMap[item.title] = ++countMap[item.title] || 1;
  return countMap;
}, {}));

1 Comment

This doesn't produce the output the OP said he wanted.
1

Given the format you want in the end, I don't think it gets much shorter than using a Map to build up objects with the title and amount, then grabbing the Map's values:

const items = [
    { title: "Trumping the Horns", value: 5.95 },
    { title: "Rocking about", value: 20.00 },
    { title: "Trumping the Horns", value: 5.95 }
];
const map = new Map();
items.forEach(item => {
  const entry = map.get(item.title);
  if (!entry) {
    map.set(item.title, {title: item.title, amount: 1});
  } else {
    ++entry.amount;
  }
});
const uniqueSales = [...map.values()];
console.log(uniqueSales);

...preferably a one-liner...

The above can be shoehorned into fewer lines, but it doesn't improve speed, readability, or maintainability. Quite the opposite.

2 Comments

Totally agree with the one-liner. Was probably a bad choice of words, my point was mostly to keep it as concise as possible and only having the least amount of, and most reasonable, steps.
@Dennis: It's worth noting that Nina's solution is less efficient than the above (unnecessary key lookup), purely so she can shoehorn it into expressions rather than statements. Now, 99.9999% of the time you don't care, but it's an example of how fewer statements != most efficient, least number of steps solution.
0

I would use a map rather than an array for storing your items, where the key of the map should be the title of the item, and the value should be the quantity of the sold items. Each time, before you add a new item to the map, you should check, whether the key already exist, and if it does, then increase the quantity, otherwise add a new key-value pair to the map.

Comments

0
 let array = [{title:"123"}, {title: "234"}, {title: "123"}]
 let sum = array.reduce((results, item, index) => {
                      let totalItem = results.find((element) =>
                            element.title == item.title)
                      if(totalItem){
                        totalItem.count += 1
                      }else {
                         results.push(Object.assign(item, {
                              count: 1
                            }))
                      }
                       return results
                     }, [])

use array reduce to generate new array

Comments

0
const ages = [3,1,1,2,3,4,1,2,3]
ages.sort();
console.log(ages);
const uniqueAges = ages.find((x, i) => {if(x!=ages[i-1]&&x!=ages[i+1]){
return x;
}} )
console.log(uniqueAges);

Output 
4

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.