I have a existing array, and now I want to change the sequence of old array according to new array's key
// Existing Array
var data = [
{
name: 'section-intro',
children: ['service-addressBox', 'service-banner']
},
{name: 'section-breadcrumb', children: ['h', 'i', 'j']},
{name: 'section-products', children: []},
{name: 'section-about', children: []},
{name: 'section-timeline', children: []},
{name: 'section-nearbyOutlets', children: []}
]
// New Array
['section-nearbyOutlets', 'section-intro', 'section-products', 'section-breadcrumb', 'section-timeline', 'section-about']
If the two arrays have the same number of elements (or if you only are interested in the elements appearing in the new one) you can try something like this using map:
// Existing Array
const data = [
{
name: 'section-intro',
children: ['service-addressBox', 'service-banner']
},
{ name: 'section-breadcrumb', children: ['h', 'i', 'j'] },
{ name: 'section-products', children: [] },
{ name: 'section-about', children: [] },
{ name: 'section-timeline', children: [] },
{ name: 'section-nearbyOutlets', children: [] }
]
// New Array
const newArray = ['section-nearbyOutlets', 'section-intro', 'section-products', 'section-breadcrumb', 'section-timeline', 'section-about']
const orderedArray = newArray.map(element => data.find(originalElement => originalElement.name === element))
console.log(JSON.stringify(orderedArray, null, 2))
Here we create a new array (orderedArray) but you can also overwrite one of the existing two if you prefer to.
You can accomplish by manually sorting by name
var temp=[]
for(let name :newarray){
for(let datum:data){
if(datum.name==name)
temp.append(datum)
}
}
data=temp
If we're talking about ordering, than you can use Array.sort
// Existing Array
let data = [
{
name: 'section-intro',
children: ['service-addressBox', 'service-banner']
},
{name: 'section-breadcrumb', children: ['h', 'i', 'j']},
{name: 'section-products', children: []},
{name: 'section-about', children: []},
{name: 'section-timeline', children: []},
{name: 'section-nearbyOutlets', children: []}
]
// New Array
const order = ['section-nearbyOutlets', 'section-intro',
'section-products', 'section-breadcrumb', 'section-timeline', 'section-about']
data = data.sort((a, b) => {
const ixa = order.indexOf(a.name)
const ixb = order.indexOf(b.name)
return ixa < ixb ? -1 : 1
})
console.log(data)
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);
i neeed to merge two arrays: Categories and Products. Each product has a category object. I need to organize by category, include the category object and keep the empty categories. GroupBy function include only one parameter.
const Categories= [
{id: 1, 'name': 'category1'}
{id: 2, 'name': 'category2'},
{id: 3, 'name': 'category3'},
{id: 4, 'name': 'category4'},
]
const Products= [
{id: 1, 'name': 'product1', category: {id: 1, name: 'category1'}},
{id: 2, 'name': 'product2', category: {id: 1, name: 'category1'}},
{id: 3, 'name': 'product3', category: {id: 2, name: 'category2'}},
{id: 4, 'name': 'product4', category: {id: 2, name: 'category2'}},
]
expected result
const result = [
{
category: {id: 1, name: 'category1'},
products:[{id:1, name: 'produt1'}, {id: 2, name: 'produto1'} ]
},
{
category: {id: 2, name: 'category2'},
products:[{id:3, name: 'produt3'}, {id: 4, name: 'produto4'} ]
},
{
category: {id: 3, name: 'category3'},
products:[]
},
{
category: {id: 4, name: 'category4'},
products:[]
},
]
attempts:
for (i = 0; i < categoriesJson.length; i++) {
categoriesJson[i] = _.assign({}, categoriesJson[i], { products: [] })
for (j = 0; j < productsJson.length; j++) {
if(productsJson[j].categoryId.objectId === categoriesJson[i].objectId){
categoriesJson[i].products.push(productsJson[j])
}
}
}
Concat the Categories (formatted by to a Product format) to the Products, group by the category.id, and then map each group - category is taken from the 1st item, while products are the the items in groups, without the category, and empty items are rejected:
const Products = [{"id":1,"name":"product1","category":{"id":1,"name":"category1"}},{"id":2,"name":"product2","category":{"id":1,"name":"category1"}},{"id":3,"name":"product3","category":{"id":2,"name":"category2"}},{"id":4,"name":"product4","category":{"id":2,"name":"category2"}}]
const Categories = [{"id":1,"name":"category1"},{"id":2,"name":"category2"},{"id":3,"name":"category3"},{"id":4,"name":"category4"}]
const result = _(Products)
.concat(Categories.map(category => ({ category })))
.groupBy('category.id')
.map(group => ({
category: _.head(group).category,
products: _(group)
.map(o => _.omit(o, 'category'))
.reject(_.isEmpty)
.value()
}))
.value()
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
And the same idea with lodash/fp. Wrap the _.flow() with the _.useWith() function, and preformat the Categories (2nd param) to fit the Categories. The rest is similar to the lodash chain.
const { useWith, identity, flow, concat, groupBy, map, head, omit, reject, isEmpty } = _
const formatProducts = flow(map(omit('category')), reject(isEmpty))
const fn = useWith(flow(
concat,
groupBy('category.id'),
map(group => ({
category: head(group).category,
products: formatProducts(group)
}))
), [identity, map(category => ({ category }))])
const Products = [{"id":1,"name":"product1","category":{"id":1,"name":"category1"}},{"id":2,"name":"product2","category":{"id":1,"name":"category1"}},{"id":3,"name":"product3","category":{"id":2,"name":"category2"}},{"id":4,"name":"product4","category":{"id":2,"name":"category2"}}]
const Categories = [{"id":1,"name":"category1"},{"id":2,"name":"category2"},{"id":3,"name":"category3"},{"id":4,"name":"category4"}]
const result = fn(Products, Categories)
console.log(result)
<script src='https://cdn.jsdelivr.net/g/lodash#4(lodash.min.js+lodash.fp.min.js)'></script>
If lodash is not a requirement in the solution, this is how I did it with plain javascript;
const Categories= [
{id: 1, 'name': 'category1'},
{id: 2, 'name': 'category2'},
{id: 3, 'name': 'category3'},
{id: 4, 'name': 'category4'}
];
const Products= [
{id: 1, 'name': 'product1', category: {id: 1, name: 'category1'}},
{id: 2, 'name': 'product2', category: {id: 1, name: 'category1'}},
{id: 3, 'name': 'product3', category: {id: 2, name: 'category2'}},
{id: 4, 'name': 'product4', category: {id: 2, name: 'category2'}},
];
const result = [];
for (let index in Categories) {
let category_id = Categories[index].id;
result.push({
category: Categories[index],
products: GetProductsWithCategoryId(category_id)
});
}
function GetProductsWithCategoryId(category_id) {
let products = [];
for (let index in Products) {
if (Products[index].category.id == category_id) {
products.push({
id: Products[index].id,
name: Products[index].name
});
}
}
return products;
}
console.log("result:", result);
Using reduce, create a mappedProducts object which groups the Products based on the category.id. Like this:
{
"1": [{ id: 1, name: "product1" }, { id: 2, name: "product2" }],
"2": [{ id: 3, name: "product3" }, { id: 4, name: "product4" }]
}
Then, map the Categories array and get the output for each category
const Categories=[{id:1,name:"category1"},{id:2,name:"category2"},{id:3,name:"category3"},{id:4,name:"category4"},],
Products=[{id:1,name:"product1",category:{id:1,name:"category1"}},{id:2,name:"product2",category:{id:1,name:"category1"}},{id:3,name:"product3",category:{id:2,name:"category2"}},{id:4,name:"product4",category:{id:2,name:"category2"}}];
const mappedProducts = Products.reduce((acc, { category, ...rest }) => {
acc[category.id] = acc[category.id] || [];
acc[category.id].push(rest)
return acc;
}, {})
const output = Categories.map(category => ({
category,
products: mappedProducts[category.id] || []
}))
console.log(output)
In a single function. Lodash is not necessary:
const Categories = [
{ id: 1, name: "category1" },
{ id: 2, name: "category2" },
{ id: 3, name: "category3" },
{ id: 4, name: "category4" }
];
const Products = [
{ id: 1, name: "product1", category: { id: 1, name: "category1" } },
{ id: 2, name: "product2", category: { id: 1, name: "category1" } },
{ id: 3, name: "product3", category: { id: 2, name: "category2" } },
{ id: 4, name: "product4", category: { id: 2, name: "category2" } }
];
function combine(categories, products) {
return categories.reduce((list, category) => {
const nextItem = {
category,
products: [
products.filter(p => p.category.id === category.id).map(
({ id, name }) => ({
id,
name
})
)
]
};
list.push(nextItem);
return list;
}, []);
}
const result = combine(Categories, Products)
Now for your information, if you had a huge list of categories and/or products, this wouldn't be the ideal solution as there is a lot of looping involved. Instead, you would cache products in such a way that you only ever need to look at a given product once (rather than looking at every product for every category). With a small data set, this optimization isn't necessary.