How to sum all Object using index with an arrays - javascript

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)

Related

Extract data from array if IDs match

I am struggling to find out a solution to my problem, but at the moment I cannot come up with the right one.
When I have my two arrays of objects I want to filter based on category IDs and extract the data from the second one into a new array for example :
const array1 = [
{id: 1, name: 'Tropical'},
{id: 2, name: 'Common'}
]
const array2 = [
{id:1, name: 'Banana', category_id: 1},
{id:2, name: 'Mango', category_id: 1},
{id:3, name: 'Apple', category_id: 2},
]
And when click happens I detect the first ID and render the new array only with data that matches the ID.
Click Tropical
New array :
[
{id:1, name: 'Banana', category_id: 1},
{id:2, name: 'Mango', category_id: 1},
]
I would be happy if someone give me a hint on how can I tackle this problem. Thanks !
Correct me if I am wrong, So you need a function that received a categoryId and you need to filter out array2 based on that category_id
You can try this
const array1 = [{
id: 1,
name: 'Tropical'
},
{
id: 2,
name: 'Common'
}
]
const array2 = [{
id: 1,
name: 'Banana',
category_id: 1
},
{
id: 2,
name: 'Mango',
category_id: 1
},
{
id: 3,
name: 'Apple',
category_id: 2
},
]
function categoryFruits(categoryId) {
return array2.filter(obj => obj.id === categoryId)
}
console.log(categoryFruits(3));
Use reduce to map over each item in array1 and filter to grab the items of that category_id
const array1 = [{
id: 1,
name: 'Tropical'
},
{
id: 2,
name: 'Common'
}
]
const array2 = [{
id: 1,
name: 'Banana',
category_id: 1
},
{
id: 2,
name: 'Mango',
category_id: 1
},
{
id: 3,
name: 'Apple',
category_id: 2
},
]
const obj = array1.reduce((acc, cur) => {
acc[cur.name] = array2.filter(v => v.category_id === cur.id)
return acc
}, {})
console.log(obj)
You could do something like filtering array2 and taking all the elements that have Tropical as name in array1.
const array1 = [
{id: 1, name: 'Tropical'},
{id: 2, name: 'Common'}
]
const array2 = [
{id:1, name: 'Banana', category_id: 1},
{id:2, name: 'Mango', category_id: 1},
{id:3, name: 'Apple', category_id: 2},
]
// take tropical friuts
let tropicalFriuts = array2.filter(x => x.category_id === array1.filter(y => y.name === 'Tropical')[0].id);
console.log(tropicalFriuts);
If I understood your problem you want before find the id, based on the name of the category, and later filter array2 data based on this id.
const array1 = [{
id: 1,
name: 'Tropical'
},
{
id: 2,
name: 'Common'
}
]
const array2 = [{
id: 1,
name: 'Banana',
category_id: 1
},
{
id: 2,
name: 'Mango',
category_id: 1
},
{
id: 3,
name: 'Apple',
category_id: 2
},
]
const id_key = array1.find(item=>item.name === 'Tropical').id;
const result = array2.filter(item=>item.category_id === id_key);
console.log(result);

add qty for similar json objects in javascript

I want the result to be summing all the qty of same cat.
var data = [
{ cat: 'EK-1',name:"test",info:"mat", quantity: 3},
{ cat: 'EK-2', name:"test2",info:"nat"quantity: 1}
];
I tried like this below i have array of object having some similar objects. how to add qty and create unque objects .below i have given what i tried.
var data = [{
cat: 'EK-1',
name: "test",
info: "mat",
quantity: 1
},
{
cat: 'EK-1',
name: "test",
info: "mat",
quantity: 1
},
{
cat: 'EK-1',
name: "test",
info: "mat",
quantity: 1
},
{
cat: 'EK-2',
name: "test2",
info: "nat",
quantity: 1
}
];
const products = Array.from(data.reduce((acc, {
cat,
quantity
}) =>
acc.set(cat, (acc.get(cat) || 0) + quantity),
new Map()
), ([cat, quantity]) => ({
cat,
quantity
}));
console.log(products);
You can do this using Array#reduce, using the accumulator to pass on the new object:
var data = [ { cat: "EK-1", name: "test", info: "mat", quantity: 1, }, { cat: "EK-1", name: "test", info: "mat", quantity: 1, }, { cat: "EK-1", name: "test", info: "mat", quantity: 1, }, { cat: "EK-2", name: "test2", info: "nat", quantity: 1, }, ];
let seen = [];
const res = data.reduce((acc, { cat, ...rest }) => {
const idx = seen.indexOf(cat);
if (idx == -1) (acc.push({cat, ...rest}), seen.push(cat));
else acc[idx].quantity++;
return acc;
}, []);
console.log(res);

How to Create Arrays of Objects With A Common Prop Value

Let's say I have an array of objects like:
flattenedObjects = [
{name: 'Bill', city: 1},
{name: 'Guillermo', city: 1},
{name: 'Wilhem', city: 1},
{name: 'William', city: 1},
{name: 'Nick', city: 2},
{name: 'Nicolas', city: 2},
{name: 'Nicholas', city: 2},
{name: 'Rick', city: 3}
]
I want to create individual arrays of objects grouped by "city". In the code, I will also deconstruct each object so that the final output will be:
boston = ['Bill', 'Guillermo', 'Wilhelm', 'William']
miami = ['Nick', 'Nickolas', 'Nicholas']
london = ['Rick']
I am having difficulties creating the grouped array of objects.
I can do it with one single object, as such:
let boston = flattenedObjects.filter(function (obj) {
return obj.city == 1;
});
What I was thinking of doing was to take a iterate through an object and filtering dynamically, like so:
let cities = {
boston: 1,
miami: 2,
london: 3
}
And then trying something like:
let newObj = flattenedObjects.filter(function (x) {
let obj = {};
Object.entries(cities).forEach(([key, value]) => {
obj["name"] = `${key}`;
obj["city"] = x.city == `${value}`;
return obj;
});
});
This isn't consoling what is expected. It's just an array of objects very similar to the "obj" up above.
let flattenedObjects = [
{name: 'Bill',city: 1},
{name: 'Guillermo',city: 1},
{name: 'Wilhem',city: 1},
{name: 'William',city: 1},
{name: 'Nick',city: 2},
{name: 'Nicolas',city: 2},
{name: 'Nicholas',city: 2},
{name: 'Rick',city: 3}
];
let cities = {
boston: 1,
miami: 2,
london: 3
}
let data = {}
for (const [key, value] of Object.entries(cities)) {
data[key] = flattenedObjects.filter(p => p.city === value).map(e => e.name);
}
console.log(data)
Create a reverse map of city code to city name, O(1) constant time lookups.
Reduce the flattenedObjects array into an object using the city name as a key and generate an array fo the names, O(n) linear access.
const flattenedObjects = [
{ name: "Bill", city: 1 },
{ name: "Guillermo", city: 1 },
{ name: "Wilhem", city: 1 },
{ name: "William", city: 1 },
{ name: "Nick", city: 2 },
{ name: "Nicolas", city: 2 },
{ name: "Nicholas", city: 2 },
{ name: "Rick", city: 3 }
];
const cities = {
boston: 1,
miami: 2,
london: 3
};
const citiesByCode = Object.fromEntries(
Object.entries(cities).map(([city, code]) => [code, city])
);
const groupedResult = flattenedObjects.reduce((groups, current) => {
const cityCode = citiesByCode[current.city];
if (!groups[cityCode]) groups[cityCode] = [];
groups[cityCode].push(current.name);
return groups;
}, {});
console.log(groupedResult);
You could use a reduce statement to reduce the flattenedObjects array into a single object in the format that you want.
const flattenedObjects = [
{name: 'Bill', city: 1},
{name: 'Guillermo', city: 1},
{name: 'Wilhem', city: 1},
{name: 'William', city: 1},
{name: 'Nick', city: 2},
{name: 'Nicolas', city: 2},
{name: 'Nicholas', city: 2},
{name: 'Rick', city: 3},
];
// the keys are the city number rather than city name
const cities = {
1: 'boston',
2: 'miami',
3: 'london',
};
const obj = flattenedObjects.reduce((o, flattenedObject) => {
const cityName = cities[flattenedObject.city];
if (o[cityName] === undefined) {
o[cityName] = [];
}
o[cityName].push(flattenedObject.name);
return o;
}, {});
console.log(obj);

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; }

How to use find() method on nested arrays?

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))

Categories