How to use find() method on nested arrays? - javascript

In this example you can see that find method works fine in this array:
var inventory = [
{name: 'apples', quantity: 2},
{name: 'bananas', quantity: 0},
{name: 'cherries', quantity: 5}
];
console.log(inventory.find(fruit => fruit.name === 'cherries'));
// { name: 'cherries', quantity: 5 }
Once I add one more level and trying to find item in it it just dont find it, it shows undefined:
var inventory = [
{name: 'apples', quantity: 2},
{name: 'bananas', quantity: 0},
{name: 'cherries', quantity: 5, type: [
{name: 'rainier', quantity: 3},
{name: 'bing', quantity: 2}
]}
];
console.log(inventory.find(fruit => fruit.name === 'bing'));
// undefined
// should be: { name: 'bing', quantity: 2 }
So I guess there is some other way to do this, but i dont know it and cant find nothing.

Your code isn't allowing for the optional type array. Assuming you want to do a depth-first search, you'd make your callback a named function and use it recursively, see comments:
var inventory = [
{name: 'apples', quantity: 2},
{name: 'bananas', quantity: 0},
{name: 'cherries', quantity: 5, type: [
{name: 'rainier', quantity: 3},
{name: 'bing', quantity: 2}
]}
];
// Define the function
function find(array, name) {
// Loop the entries at this level
for (const entry of array) {
// If we found it, return it
if (entry.name === name) {
return entry;
}
// If not but there's a type array, recursively search it
if (Array.isArray(entry.type)) {
const found = find(entry.type, name);
if (found) {
// Recursive search found it, return it
return found;
}
}
}
// If execution falls off the end, it's effectively `return undefined;`
}
console.log(find(inventory, 'bing'));

inventory.find will only find element of array with given conditions in the inventory and because {name: 'bing', quantity: 2} is not present in inventory so it will return undefined
.You can do that using recursion
var inventory = [
{name: 'apples', quantity: 2},
{name: 'bananas', quantity: 0},
{name: 'cherries', quantity: 5, type: [
{name: 'rainier', quantity: 3},
{name: 'bing', quantity: 2}
]}
];
function findFruitWithName(arr,name){
let x = arr.find(fruit => fruit.name === name);
if(x === undefined){
for(let fruit of arr){
if(fruit.type) {
let y = findFruitWithName(fruit.type,name);
if(y !== undefined) return y
}
}
}
else return x;
}
console.log(findFruitWithName(inventory,'bing'))
// undefined
// should be: { name: 'bing', quantity: 2 }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>

You are right in that find only looks at the elements in the array and doesn't look in the nested ones, so you have to create your own.
You could loop over all the items in the inventory and collect all the elements in the potential type arrays and continue to loop over them until you find an item with the desired name, or return undefined if you check all items and you don't find a match.
Example
const inventory = [
{ name: "apples", quantity: 2 },
{ name: "bananas", quantity: 0 },
{
name: "cherries",
quantity: 5,
type: [{ name: "rainier", quantity: 3 }, { name: "bing", quantity: 2 }]
}
];
function findItem(inventory, name) {
let items = [...inventory];
let item;
while (items.length !== 0) {
item = items.pop();
if (item.name === name) {
return item;
} else if (item.type) {
items.push(...item.type);
}
}
return undefined;
}
console.log(findItem(inventory, "bing"));

try this
var inventory = [
{name: 'apples', quantity: 2},
{name: 'bananas', quantity: 0},
{name: 'cherries', quantity: 5, type: [
{name: 'rainier', quantity: 3},
{name: 'bing', quantity: 2}
]}
];
var name = 'bing'
var result = inventory.find((fruit) => {
if(fruit.name === name) return true
if(fruit.type) return fruit.type.find(type=>type.name===name)
return false
})
console.log(result)
UPDATE:
if you want it to make it recursive you can try
function find(name, inventory) {
return inventory.find((fruit) => {
if(fruit.name === name) return true
if(fruit.type) return find(name, fruit.type)
return false
})
}
console.log(find(name,inventory))

Related

How to sum all Object using index with an arrays

how can I search duplicate data using index key object here is my object :
const obj = {
product1: { name: 'paper', price: 4 },
product2: { name: 'ball', price: 2 },
product3: { name: 'ice-cream', price: 9 }
product1: { name: 'paper', price: 2 }
}
and I have an arrays
const arr = ["product1", "product2" ]
I want to get only product1 and product2 data then sum price together my output shold look like this 4+2+2 = 8
Here is what I try to do
const newArr = _.map(arr, (name:string) => {
return obj[name]
})
then I sum
const sum = newArr.reduce((data, obj)=> data + obj.price, 0);
the problem is in _.map when I map data if I return like this it will get only 1 product1 I want to get all of product name in arr
### UPDATE ####
I changed my object to unique but I still want to use arr to find some word not sure Can I use includes or indexOf in and Objects?
const obj = {
"product1 Hello": { name: 'paper', price: 4 },
"product2 test": { name: 'ball', price: 2 },
"product3 Hello3": { name: 'ice-cream', price: 9 }
"product1 Hello4": { name: 'paper', price: 2 }
}
I would use Array.prototype.reduce to iterate through the array and return a single value that is the total price.
const products = {
id1: { name: "paper", price: 4 },
id2: { name: "ball", price: 2 },
id3: { name: "ice-cream", price: 9 },
};
const productIds = ["id1", "id2"];
const totalPrice = productIds.reduce((sum, id) => {
return sum + products[id].price;
}, 0);
Non lodash implementation. filtered the array and ran reduce
const arr = ["product1", "product2" ]
const obj2 = {
"product1 Hello": { name: 'paper', price: 4 },
"product2 test": { name: 'ball', price: 2 },
"product3 Hello3": { name: 'ice-cream', price: 9 },
"product1 Hello4": { name: 'paper', price: 2 }
}
let filtered = Object.entries(obj2).filter((el) => arr.includes(el[0].split(" ")[0]))
const sum = filtered.reduce((acc,curr)=> acc + curr[1].price, 0);
console.log(sum)
Your problem is that the obj will never contain the key product1 twice. When that object is created during runtime the last value of product1 is what is stored in the object. Even if you had a JSON object with those two keys, when you go to parse it, the last key will be the value. The only way I can think to do what you want is that you need to change the data prior to the object being created.
You added to unique keys, which isn't going to help you as now you'll need to iterate through all the keys to make sure you are getting all of them. You are better off putting the key in the object, and use an array of objects.
const obj = [
{key: 'product1', name: 'paper', price: 4},
{key: 'product2', name: 'ball', price: 2},
{key: 'product3', name: 'ice-cream', price: 9},
{key: 'product1', name: 'paper', price: 2},
]
You can then use Array.reduce to combine the values, or other methods.
Now to get only product 1 and 2 use filter:
const desiredProducts = obj.filter(p => ['product1','product2'].includes(p.key));
``
Or you can combine any matching keys using Array.reduce()
```js
const combinedResult = obj.reduce((cur, acc) => {
const s = cur.find(c => c.key === acc.key);
if (s)
s.price += acc.price;
else
cur.push(acc);
}, []);
JSON object can't hold duplicate keys. If so, it gets replaced by the last record.
In your case, the input becomes:
const obj = {
product1: { name: 'paper', price: 2 },
product2: { name: 'ball', price: 2 },
product3: { name: 'ice-cream', price: 9 }
}
Your possible input will be like thes:
const obj = {
product1: [{ name: 'paper', price: 4 }, { name: 'paper', price: 2 }],
product2: [{ name: 'ball', price: 2 }],
product3: [{ name: 'ice-cream', price: 9 }]
}
const obj = [
{key: 'product1', name: 'paper', price: 4},
{key: 'product2', name: 'ball', price: 2},
{key: 'product3', name: 'ice-cream', price: 9},
{key: 'product1', name: 'paper', price: 2},
]
Updated answer as updated code:
const obj = {
"product1 Hello": {name: 'paper', price: 4},
"product2 test": {name: 'ball', price: 2},
"product3 Hello3": {name: 'ice-cream', price: 9},
"product1 Hello4": {name: 'paper', price: 2}
}
const arr = ["product1", "product2"]
let keys = Object.keys(obj).filter(x => arr.some(y => x.includes(y)))
keys.map(x => obj[x].price).reduce((x, y) => x + y, 0)

Converting array of object to hierarchical data structure

I have an original array and I want to plot it in Sunburst map which needs a hierarchical data structure.
[
{id: "Asia,India,NewDelhi", value: 41},
{id: "Europe,Germany,Berlin", value: 24},
{id: "Europe,England,London", value: 3},
{id: "NorthAmerica,USA,NewYork", value: 4},
{id: "NorthAmerica,USA,Boston", value: 3},
{id: "NorthAmerica,USA,chicago", value: 3},
{id: "Austrailia,Sydney", value: 4},
{id: "Asia,China,Beijing", value: 2},
]
Desired Result
[
{
id: Asia,
children:[{
id: India,
children:[{
id: Delhi,
value: 41,
}]
},
{
id:China,
children:[{
id: Beijing
value: 2,
}]
}]
},
{
id: Europe,
children: [{
id: Germany,
children: [{
id: Berlin,
value: 24,
}]
},
{
id: England,
children: [{
id: London,
value: 3,
}]
}]
},
{
id: NorthAmerica,
children:[{
id: USA,
children:[{
id: NewYork,
value: 4,
},
{
id: Boston,
value: 3,
},
{
id: Chicago,
value: 3,
}]
}]
},
{
id: Austrailia
children: [{
id:Sydney,
value: 4,
}]
},
]
can anyone help me with this, I tried using reduce method but I am not able to get the desired result.
PS : It would be super useful if anyone could suggest an answer that would deal with n number of ids separated by commas. For ex: here we have 3 id hierarchy separated by commas, what would happen if there were 4 or 5 depth data.
A simple solution with recursion:
const data = [
{id: "Asia,India,NewDelhi", value: 41},
{id: "Europe,Germany,Berlin", value: 24},
{id: "Europe,England,London", value: 3},
{id: "NorthAmerica,USA,NewYork", value: 4},
{id: "NorthAmerica,USA,Boston", value: 3},
{id: "NorthAmerica,USA,Chicago", value: 3},
{id: "Austrailia,Sydney", value: 4},
{id: "Asia,China,Beijing", value: 2},
];
const addChild = (ids, value, arr) => {
const id = ids.shift();
let index = arr.findIndex(item => item.id === id);
if (index < 0) {
arr.push({id, children: []});
index = arr.length - 1;
}
if (ids.length > 0) {
const children = arr[index].children;
addChild(ids, value, children);
}
else
arr[index].value = value;
}
const treeData = data.reduce((tree, item) => {
const ids = item.id.split(',');
addChild(ids, item.value, tree);
return tree;
}, []);
console.log(treeData);
To build a hierarchy of objects from your input is fairly straightforward, you dont even need to do anything recursive a loop + reduce will do it. This will work with any number of levels in your comma separated list.
const input = [
{id: "Asia,India,NewDelhi", value: 41},
{id: "Europe,Germany,Berlin", value: 24},
{id: "Europe,England,London", value: 3},
{id: "NorthAmerica,USA,NewYork", value: 4},
{id: "NorthAmerica,USA,Boston", value: 3},
{id: "NorthAmerica,USA,chicago", value: 3},
{id: "Austrailia,Sydney", value: 4},
{id: "Asia,China,Beijing", value: 2}
]
const result = input.map(o => ({ids:o.id.split(","), value:o.value})).reduce( (acc,obj) => {
let curr = acc;
let id;
while( (id = obj.ids.shift()) != null ){
if(!curr[id])
curr[id] = {};
curr = curr[id];
}
curr.value = obj.value
return acc;
},{});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
To then turn this into the format you wanted does take a bit of recursion:
const input = [
{id: "Asia,India,NewDelhi", value: 41},
{id: "Europe,Germany,Berlin", value: 24},
{id: "Europe,England,London", value: 3},
{id: "NorthAmerica,USA,NewYork", value: 4},
{id: "NorthAmerica,USA,Boston", value: 3},
{id: "NorthAmerica,USA,chicago", value: 3},
{id: "Austrailia,Sydney", value: 4},
{id: "Asia,China,Beijing", value: 2}
]
const result = input.map(o => ({ids:o.id.split(","), value:o.value})).reduce( (acc,obj) => {
let curr = acc;
let id;
while( (id = obj.ids.shift()) != null ){
if(!curr[id])
curr[id] = {};
curr = curr[id];
}
curr.value = obj.value
return acc;
},{});
function buildHierarchy(input){
return Object.entries(input).map( ([id,children]) => {
if(children.value){
return {id,value:children.value}
}
return {id, children: buildHierarchy(children)}
})
}
console.log(buildHierarchy(result));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Iterating on nested arrays in objects to collate informaton

I have the following array of objects:
let array = [
{key: 'Newcastle', values[
{key: 'ID1000', values[
{name: 'Jeff', cust_id: "ID1000", status: 'sold'},
{name: 'Jeff', cust_id: "ID1000", status: 'pending'},
]}
{key: 'ID2000', values [
{name: 'Bob', cust_id: "ID2000", status: 'sold'}
]}
]}
{key: 'London', values [
{key: 'ID3000', values[
{name: 'Gary', cust_id: "ID3000", status: 'sold'},
]}
{key: 'ID4000', values[
{name: 'Mary', cust_id: "ID4000", status: 'interest'},
{name: 'Mary', cust_id: "ID4000", status: 'interest'},
{name: 'Mary', cust_id: "ID4000", status: 'pending'},
]}
]}
]
I have been trying to refactor it into something like:
[
{Location: 'Newcastle, customers: 2, sold: 2, pending: 1, interest: 0},
{Location: 'London', customers: 2, sold: 1, pending: 1, interest: 2}
]
So I am attempting to count the number of status events and collate them accordingly.
I get lost when I try to iterate on the nested arrays and then when trying to bubble up the results of the iteration to a final object. The closest I have got is:
function transform(array) {
let arr = []
array.forEach(function(x) {
function soldCount() {
x.values.forEach(function(x) {
let sold = x.values.forEach(function(x) {
let soldTrue = 0
if (x.status === "sold") {
soldTrue++
}
console.log(soldTrue)
if (soldTrue > 0) {
return soldTrue
}
})
})
}
let obj = {
location: x.key,
customers: x.values.length,
sold: soldCount()
}
arr.push(obj)
})
return arr
}
This tries to iterate on each array in the objects and attempts to return a number for how many of the 'sold' status it finds. The console statement does return a number but it returns multiple entries for each item in the array due to 'forEach'.
I am swamped in a number of forEach loops iterating on nested arrays. I suspect that this might not be the correct methodology for what I am trying to achieve.
You could take an object counting status and build a new objects.
var array = [{ key: 'Newcastle', values: [{ key: 'ID1000', values: [{ name: 'Jeff', cust_id: "ID1000", status: 'sold' }, { name: 'Jeff', cust_id: "ID1000", status: 'pending' },] }, { key: 'ID2000', values: [{ name: 'Bob', cust_id: "ID2000", status: 'sold' }] }] }, { key: 'London', values: [{ key: 'ID3000', values: [{ name: 'Gary', cust_id: "ID3000", status: 'sold' },] }, { key: 'ID4000', values: [{ name: 'Mary', cust_id: "ID4000", status: 'interest' }, { name: 'Mary', cust_id: "ID4000", status: 'interest' }, { name: 'Mary', cust_id: "ID4000", status: 'pending' }] }] }],
result = array.map(({ key: Location, values }) => {
var data = { Location, customers: 0, sold: 0, pending: 0, interest: 0 };
values.forEach(({ values }) => {
data.customers++;
values.forEach(({ status }) => data[status]++);
});
return data;
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Look at this:
let array = [
{
key: 'Newcastle',
values: [
{key: 'ID1000',
values:[
{name: 'Jeff', cust_id: "ID1000", status: 'sold'},
{name: 'Jeff', cust_id: "ID1000", status: 'pending'},
]},
{
key: 'ID2000',
values :[
{name: 'Bob', cust_id: "ID2000", status: 'sold'}
]
}
]},
{key: 'London', values :[
{key: 'ID3000', values:[
{name: 'Gary', cust_id: "ID3000", status: 'sold'},
]},
{key: 'ID4000', values:[
{name: 'Mary', cust_id: "ID4000", status: 'interest'},
{name: 'Mary', cust_id: "ID4000", status: 'interest'},
{name: 'Mary', cust_id: "ID4000", status: 'pending'},
]}
]}
]
function countProp(arr, prop) {
let n = 0;
arr.forEach((items) => {
items.values.forEach(item => {
if (item.status === prop) {
n += 1;
}
})
});
return n;
}
const n = array.map(item => {
const a = {};
a.customers = item.values.length;
a.location = item.key;
a.sold = countProp(item.values, "sold");
a.pending = countProp(item.values, "pending");
a.interest = countProp(item.values, "interest");
return a;
});
This gives
[
{Location: 'Newcastle, customers: 2, sold: 2, pending: 1, interest: 0},
{Location: 'London', customers: 2, sold: 1, pending: 1, interest: 2}
]
Assumingly you are using let.
I have written my solution in ES6, getting Location, customer count is easy.
The challenging part would be the accumulating the status count per type of status, you can use reduce with object as initial value and using the status types as keys with 0 initial value, which shown in my solution
let array = [
{key: 'Newcastle', values: [
{key: 'ID1000', values: [
{name: 'Jeff', cust_id: "ID1000", status: 'sold'},
{name: 'Jeff', cust_id: "ID1000", status: 'pending'}
]},
{key: 'ID2000', values: [
{name: 'Bob', cust_id: "ID2000", status: 'sold'}
]}
]},
{key: 'London', values: [
{key: 'ID3000', values: [
{name: 'Gary', cust_id: "ID3000", status: 'sold'}
]},
{key: 'ID4000', values:[
{name: 'Mary', cust_id: "ID4000", status: 'interest'},
{name: 'Mary', cust_id: "ID4000", status: 'interest'},
{name: 'Mary', cust_id: "ID4000", status: 'pending'}
]}
]}
];
const newArray = array.map((a) => {
const Location = a.key;
const customer = a.values.length;
const status = a.values.reduce((acc, value) => {
value.values.forEach((v1) => {
acc[v1.status] = acc[v1.status] + 1;
});
return acc;
}, {sold: 0, pending: 0, interest: 0});
return {Location, customer, ...status};
});
console.log(newArray);

How to return not all of the properties of an object from arrays with an array method?

I want to use an array method with arrow function. For an example:
const inventory = [
{name: 'apples', quantity: 2, type: 'a'},
{name: 'bananas', quantity: 0, type: 'a'},
{name: 'cherries', quantity: 5, type: 'a'}
{name: 'mangos', quantity: 5, type: 'a'}
];
const result = inventory.filter( fruit => fruit.quantity === 5 );
What if i want to return just the object with the name and type properties? Like this:
console.log(result) //[{name: 'mangos', type: 'a'}, {name: 'cherries', type: 'a'}]
You'd create a new object. It looks like you want to do two things, though: Filter to only items with quantity of 5, and return objects without the quantity field. Unelss you have hundreds of thousands of these¹, you'd do that by using filter then map. Here's an example with destructuring:
const inventory = [
{name: 'apples', quantity: 2, type: 'a'},
{name: 'bananas', quantity: 0, type: 'a'},
{name: 'cherries', quantity: 5, type: 'a'},
{name: 'mangos', quantity: 5, type: 'a'}
];
const result = inventory
.filter(fruit => fruit.quantity === 5)
.map(({name, type}) => ({name, type}));
console.log(result);
¹ If you do have hundreds of thousands of these or more, you might consider just making one pass with forEach.
inventory.filter(fruit => fruit.quantity === 5).map(fruit => ({ name: fruit.name, type: fruit.type }));
map creates a new array using the values you give it, but doesn't change the original, filter creates an array using only the values the function returned a truthy value for.
You can remove the type property by destructuring:
const inventory = [
{name: 'apples', quantity: 2, type: 'a'},
{name: 'bananas', quantity: 0, type: 'a'},
{name: 'cherries', quantity: 5, type: 'a'},
{name: 'mangos', quantity: 5, type: 'a'}
];
const res = inventory.map(({type: x, ...rest}) => rest);
console.log(res);
Or you can just make your array.map callback returning object having only name and quantity field:
const inventory = [
{name: 'apples', quantity: 2, type: 'a'},
{name: 'bananas', quantity: 0, type: 'a'},
{name: 'cherries', quantity: 5, type: 'a'},
{name: 'mangos', quantity: 5, type: 'a'}
];
const res = inventory.map(({name, quantity}) => ({name, quantity}));
console.log(res);
Try using lodash
const inventory = [
{name: 'apples', quantity: 2, type: 'a'},
{name: 'bananas', quantity: 0, type: 'a'},
{name: 'cherries', quantity: 5, type: 'a'}
{name: 'mangos', quantity: 5, type: 'a'}
];
const result = ._map( inventory, (item)=> {
return {
name: item.name,
quantity: item.quantity}
} );

Add and combine duplicates in array of objects with lodash with specific conditions

Say I have a sorted array of objects like this:
[
{name: 'item1', quantity: 5},
{name: 'item1', quantity: 8},
{name: 'item2', quantity: 6},
{name: 'item2', quantity: 3},
{name: 'item3', quantity: 1},
{name: 'item3', quantity: 1},
]
I want to add up the values of items which have quantities > 1 and combine them so I get this:
[
{name: 'item1', quantity: 13},
{name: 'item2', quantity: 9},
{name: 'item3', quantity: 1},
{name: 'item3', quantity: 1},
]
Is there a quick single or chain of lodash methods that can achieve this? I was thinking to use _.map but it doesn't give you previous item, so I'd have to use a variable outside the _.map scope to keep that value. Seeing if I can do this with lodash since I'm already using it for other methods and not write extra lines of code.
If the extra condition is not possible, then combining and adding all items will have to do.
This is my attempt using only lodash:
var source = [
{name: 'item1', quantity: 5},
{name: 'item1', quantity: 8},
{name: 'item2', quantity: 6},
{name: 'item2', quantity: 3},
{name: 'item3', quantity: 1},
{name: 'item3', quantity: 1},
];
var predicate = function (e) {
return e.quantity > 1;
};
var result = _.chain(source)
.filter(predicate)
.groupBy(function (e) {
return e.name;
})
.map(function (group) {
return _.reduce(group, function (current, next) {
return {
name: next.name,
quantity: current.quantity + next.quantity
};
});
})
.union(_.filter(source, function (e) {
return !predicate(e);
}))
.value();
document.getElementById("output").textContent = JSON.stringify(result, 0, 2);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.6.1/lodash.min.js"></script>
<pre id="output"></pre>
Not sure if this is the most efficient way, as I'm not deeply familiar with lodash. Basically, the idea is this:
Get the elements with quantity > 1
Group by name
Produce sums for each name
Union with the elements with quantity <= 1
Fiddle
Here is a pure lodash-ian solution :)
It uses chain, reduce, toPairs, map and 1 temporary variable to do the job.
items = [
{name: 'item1', quantity: 5},
{name: 'item1', quantity: 8},
{name: 'item2', quantity: 6},
{name: 'item2', quantity: 3},
{name: 'item3', quantity: 1},
{name: 'item3', quantity: 1}
];
summary = _.chain(items).reduce(function(acc, i) {
if (i.quantity > 0) {
acc[i.name] = (acc[i.name] || 0) + i.quantity;
}
return acc;
}, {}).toPairs().map(function(x) {
var tmp = {};
tmp[x[0]] = x[1];
return tmp;
}).value();
console.log(JSON.stringify(summary));
// Outputs: [{"item1":13},{"item2":9},{"item3":2}]
Another solution in plain Javascript with a single loop.
var data = [{ name: 'item1', quantity: 5 }, { name: 'item1', quantity: 8 }, { name: 'item2', quantity: 6 }, { name: 'item2', quantity: 3 }, { name: 'item3', quantity: 1 }, { name: 'item3', quantity: 1 }],
combined = function (array) {
var r = [];
array.forEach(function (a, i) {
if (a.quantity === 1) {
r.push(a);
return;
}
if (!this[a.name]) {
this[a.name] = { name: a.name, quantity: 0 };
r.push(this[a.name]);
}
this[a.name].quantity += a.quantity;
}, {});
return r;
}(data);
document.write('<pre>' + JSON.stringify(combined, 0, 4) + '</pre>');
You can use Array.prototype.forEach() , for loop
var arr = [
{name: 'item1', quantity: 5},
{name: 'item1', quantity: 8},
{name: 'item2', quantity: 6},
{name: 'item2', quantity: 3},
{name: 'item3', quantity: 1},
{name: 'item3', quantity: 1},
];
var res = [];
arr.forEach(function(item, index) {
if (res.length === 0
|| !res.some(function(elem) {return elem.name === item.name})
|| item["quantity"] === 1 ) {
res.push(item)
} else {
for (var i = 0; i < res.length; i++) {
if (res[i]["name"] === item["name"]
&& (res[i]["quantity"] !== 1 && item["quantity"] !== 1)) {
res[i]["quantity"] += item["quantity"]
}
}
}
});
document.querySelector("pre").textContent = JSON.stringify(res, null, 2)
<pre></pre>

Categories