1

I have an array as follows:

const array = [
{id: 3, amount: 100, productId: 10, title: "Color/Red", variantChildren: Array(0)},
{id: 4, amount: 5, productId: 10, title: "Color/Green", variantChildren: Array(2)},
{amount: 0, variantChildren: {…}, title: "Color/Red"},
{amount: 0, variantChildren: {…}, title: "Color/Green"},
{amount: 0, variantChildren: {…}, title: "Color/Purple"}
]

I need to remove the duplicates that have the amount of 0. I'm trying to figure out how to do this with .filter() or .forEach()

So items [2] & [3] would get removed, and returned with a new array:

const newArray = [
{id: 3, amount: 100, productId: 10, title: "Color/Red", variantChildren: Array(0)},
{id: 4, amount: 5, productId: 10, title: "Color/Green", variantChildren: Array(2)},
{amount: 0, variantChildren: {…}, title: "Color/Purple"}
]
6
  • 1
    why not item at index 4? Commented Jan 28, 2021 at 17:49
  • 1
    Please use standard syntax when displaying data. The easiest way of getting that is to use console.log(JSON.stringify(objToLog, null, 2)). Otherwise, we have to wade through comments complaining about syntax where we just don't need to. Commented Jan 28, 2021 at 17:49
  • @vr12 because the title is unique, ie: 'Color/Purple'. 2 & 3 should get removed because there are duplicates of 'color/red' and 'color/green', but their amount is 0. Commented Jan 28, 2021 at 17:50
  • So, group on title, remove the ones that have amount 0? Commented Jan 28, 2021 at 17:51
  • how do you choose the one selected in duplicates? It's the last one? Commented Jan 28, 2021 at 17:51

4 Answers 4

1

Reduce the array to a Map, only add items that don't exist, or those that exist, and those that exist, but have a total greater than 0.

Convert the Map's .values() iterator to an array with Array.from().

const data = [{"id":3,"amount":100,"productId":10,"title":"Color/Red","variantChildren":[]},{"id":4,"amount":5,"productId":10,"title":"Color/Green","variantChildren":[null,null]},{"amount":0,"variantChildren":{},"title":"Color/Red"},{"amount":0,"variantChildren":{},"title":"Color/Green"},{"amount":0,"variantChildren":{},"title":"Color/Purple"}];

const result = Array.from(
  data.reduce((acc, o) =>
    !acc.has(o.title) || o.amount > 0 ? acc.set(o.title, o) : acc, new Map())
  .values()
);

console.log(result);

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

Comments

1

const data = [
  {id: 3, amount: 100, productId: 10, title: "Color/Red", variantChildren: Array(0)},
  {id: 4, amount: 5, productId: 10, title: "Color/Green", variantChildren: Array(2)},
  {amount: 0, variantChildren:{}, title: "Color/Red"},
  {amount: 0, variantChildren: {}, title: "Color/Green"},
  {amount: 0, variantChildren: {}, title: "Color/Purple"},
  {id: 5, amount: 3, productId: 11, title: "Color/Green", variantChildren: Array(2)},
  {id: 6, amount: 10, productId: 12, title: "Color/Red", variantChildren: Array(0)},
  {amount: 2, variantChildren: {}, title: "Color/Purple"},
  {amount: 0, variantChildren: {}, title: "Color/Purple"},
];

const removeZeroAmountDuplicates = arr => {
  // group items by title
  const titleItemsMap = arr.reduce((acc,item) => {
    const { title, amount } = item;
    if(acc[title]) acc[title].push(item);
    else acc[title] = [item];
    return acc;
  }, {});
  // iterate over each title's items
  const res = Object.values(titleItemsMap).reduce((acc, titleItems) => {
    // if list has more than one elements remove zero-amount items, otherwise keep the only element
    const items = titleItems.length > 1
      ? titleItems.filter(item => item.amount !== 0)
      : titleItems;
    // merge items with acc
    return [...acc, ...items]
  }, []);
  return res;
}

console.log( removeZeroAmountDuplicates(data) );

3 Comments

Running your snippet still removed the 'Color/Purple'
Should be return !acc
@Dileet I updated the answer to cover your conditions
0

var unfiltered = [{amount: 0}, {amount: 0}, {amount: 1}, {amount: 2}]
var tmpArray = [];
var filtered = unfiltered.filter((val, index, arr) => {
  var tmpTrue = !(tmpArray.map(v => v.amount).includes(val.amount))
  tmpArray.push(val)
  return tmpTrue;
});
console.log(filtered);

Filter MDN

That code is kind of unreadable. Basically, filter maps through the array. The function provided should return true or false. If true, return the current value to the new array, otherwise, skip it. The function I provided maps through the temporary array, which gets updated every value, since we need to check the amount for each element. So the mapped array return amount for every element. With the new array, we check if amount already exists, true or false.

2 Comments

Hmm I'm getting an empty array from this
@Dileet I updated it, I had the wrong idea for filter
0

for using .filter or .forEach you have to check each elements and if this element can find in lower index, remove it.

const array = [
    {id: 3, amount: 100, productId: 10, title: "Color/Red"},
    {id: 4, amount: 5, productId: 10, title: "Color/Green"},
    {amount: 0, title: "Color/Red"},
    {amount: 0, title: "Color/Green"},
    {amount: 0, title: "Color/Purple"}
]

const result = array.filter((el, i) => {
    const dupIndex = array.findIndex(e => e.amount === el.amount)
    return i <= dupIndex
})

console.log(result)

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.