Related
I'm attempting to create an array of objects as the final output which includes the parent name and it's children. The id would be the last child in the name
Sample output I'm trying to achieve :
[
{id:1,name:"1"},
{id:2,name:"1-2"},
{id:3,name:"1-2-3"},
{id:4,name:"1-2-4"}
]
Code:
let item = {
id: 1,
name: "1",
children: [{
id: 2,
name: "2",
children: [{
id: 3,
name: "3",
children: []
},
{
id: 4,
name: "4",
children: []
}
]
}]
}
const createList = (item) => {
let name = item.children.map(e => {
return createList(e)
})
return item.name + "-" + name
}
console.log(createList(item))
A simple recursion will do the trick:
let item = {
id: 1,
name: "1",
children: [{
id: 2,
name: "2",
children: [{
id: 3,
name: "3",
children: []
},
{
id: 4,
name: "4",
children: []
}
]
}]
}
var result = []
const createList = (items, acc) => {
items.forEach(item => {
const newAcc = {
id: item.id,
name: acc ? `${acc.name}-${item.name}` : `${item.name}`
}
result.push(newAcc)
createList(item.children, newAcc)
})
}
createList([item], null)
console.log(result)
You're on the right track with recursion, but the map function is probably not the best choice for this. Map function doesn't work the way you might expect when there is only one element in the array, as it is not meant to be used to process lists in such a way, but only to "map" data.
Try switching to a for loop or foreach and building the string yourself.
Example:
let sample = {
id: 1,
name: "1",
children: [{
id: 2,
name: "2",
children: [{
id: 3,
name: "3",
children: []
},
{
id: 4,
name: "4",
children: []
}
]
}]
};
function buildArray(input, parentName) {
let output = [];
for (let item of input) {
let name = parentName ? `${parentName}-${item.name}` : item.name;
output.push({ id: item.id, name: name });
if (item.children) {
output = output.concat(buildArray(item.children, name));
}
}
return output;
}
let result = buildArray(sample.children, sample.name);
let output = document.getElementById('myresult');
output.innerText = JSON.stringify(result);
<p id="myresult"></p>
I think we can do this more simply. I'd prefer code like this:
const convert = ({id, name, children}, prefix = '') => [
{id, name: prefix + name},
...children .flatMap (c => convert (c, prefix + name + '-'))
]
const sample = {id: 1, name: "1", children: [{id: 2, name: "2", children: [{id: 3, name: "3", children: []}, {id: 4, name: "4", children: []}]}]}
console .log (convert (sample))
.as-console-wrapper {max-height: 100% !important; top: 0}
Note that our recursion bottoms without an explicit case for it because mapping over an empty array returns an empty array, without making further calls. And that result is just folded into our accumulation by flatMap.
If you prefer not to include default parameters (and there are some good reasons for that preference), you could simply wrap an internal version of this function into a public function, supplying the initial prefix value to that internal one. This would also allow us to simplify the function reference passed to flatMap:
const _convert = (prefix = '') => ({id, name, children}) => [
{id, name: prefix + name},
...children .flatMap (_convert (prefix + name + '-'))
]
const convert = _convert ('')
const sample = {id: 1, name: "1", children: [{id: 2, name: "2", children: [{id: 3, name: "3", children: []}, {id: 4, name: "4", children: []}]}]}
console .log (convert (sample))
.as-console-wrapper {max-height: 100% !important; top: 0}
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)
I have an array
data = [
{code: 'A1', name: 'bag', qty: 3},
{code: 'A2', name: 'purse', qty: 2},
{code: 'A3', name: 'belt', qty: 1},
]
I want to omit qty & duplicate each item to another array based on each qty :
data = [
{code: 'A1', name: 'bag'},
{code: 'A1', name: 'bag'},
{code: 'A1', name: 'bag'},
{code: 'A2', name: 'purse'},
{code: 'A2', name: 'purse'},
{code: 'A3', name: 'belt'},
]
I've tried :
const [qtyList, setQtyList] = useState(
new Array(renderData.length).fill(1)
);
const [selectedProduct, setSelectedProduct] = useState([])
const updatedQty = qtyList.map((q, index) => {
if (index === k) return q = parseInt(val)
else return q
});
setQtyList(updatedQty); //[3,2,1]
data.map((i, idx) => {
let temp = []
let existed = data.filter(x=>x.code==i.code).length
for (let x=0; x<=qtyList[idx]; x++){
temp.push(i)
}
setSelectedProduct((prev)=> [...prev, i])
}
Use the following code:
var data = [
{ code: 'A1', name: 'bag', qty: 3 },
{ code: 'A2', name: 'purse', qty: 2 },
{ code: 'A3', name: 'belt', qty: 1 },
];
var newArray = data.map(x => {
return Array(x.qty).fill({ code: x.code, name: x.name })
})
console.log([].concat.apply([], newArray))
An example using flatMap
const data = [
{ code: "A1", name: "bag", qty: 3 },
{ code: "A2", name: "purse", qty: 2 },
{ code: "A3", name: "belt", qty: 1 },
];
const o = data.flatMap(({ code, name, qty }) =>
Array(qty).fill({ code, name })
);
console.log(o);
data.map(item => Array(item.qty).fill({ code: item.code, name: item.name })).flat();
Use this code
data.reduce((a,{qty, ...rest})=>a.concat(Array(qty).fill({...rest})),[]);
There is probably a more elegant solution to this problem, but this was my quick fix:
let data = [
{code: 'A1', name: 'bag', qty: 3},
{code: 'A2', name: 'purse', qty: 2},
{code: 'A3', name: 'belt', qty: 1},
]
let dupArr = []
data.map((i) =>{
for(let j = 0;j<= i['qty']-1; j++){
dupArr.push(i);
}
});
dupArr.map((idx)=>{
delete idx['qty'];
})
console.log(dupArr);
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);
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; }