This question already has answers here:
Group array items using object
(19 answers)
Closed 6 years ago.
I'm trying to group the raw data from:
items:
[
{
category: "blog",
id : "586ba9f3a36b129f1336ed38",
content : "foo, bar!"
},
{
category: "blog",
id : "586ba9f3a36b129f1336ed3c",
content : "hello, world!"
},
{
category: "music",
id : "586ba9a6dfjb129f1332ldab",
content : "wow, shamwow!"
},
]
to
[
{
category: "blog",
items:
[
{
id : "586ba9f3a36b129f1336ed38",
content : "foo, bar!"
},
{
id : "586ba9f3a36b129f1336ed3c",
content : "hello, world!"
},
]
},
{
category: "music",
items:
[
{
id : "586ba9a6dfjb129f1332ldab",
content : "wow, shamwow!"
}
]
}
]
The format like this helps me to print the same category data together in the frontend.
The content of the category field is dynamically, so I'm not sure how do I store it to a temporary object and sort them, any thoughts?
(I can't think a better title for the question, please edit if you got a better title.)
You can do it using Array#reduce in one pass:
var items = [{"category":"blog","id":"586ba9f3a36b129f1336ed38","content":"foo, bar!"},{"category":"blog","id":"586ba9f3a36b129f1336ed3c","content":"hello, world!"},{"category":"music","id":"586ba9a6dfjb129f1332ldab","content":"wow, shamwow!"}];
var result = items.reduce(function(r, item) {
var current = r.hash[item.category];
if(!current) {
current = r.hash[item.category] = {
category: item.category,
items: []
};
r.arr.push(current);
}
current.items.push({
id: item.id,
content: item.content
});
return r;
}, { hash: {}, arr: [] }).arr;
console.log(result);
Or the ES6 way using Map:
const items = [{"category":"blog","id":"586ba9f3a36b129f1336ed38","content":"foo, bar!"},{"category":"blog","id":"586ba9f3a36b129f1336ed3c","content":"hello, world!"},{"category":"music","id":"586ba9a6dfjb129f1332ldab","content":"wow, shamwow!"}];
const result = [...items.reduce((r, { category, id, content }) => {
r.has(category) || r.set(category, {
category,
items: []
});
r.get(category).items.push({ id, content });
return r;
}, new Map).values()];
console.log(result);
Personally, without any helper libraries, I'd just do this
var step1 = items.reduce((result, {category, id, content}) => {
result[category] = result[category] || [];
result[category].push({id, content});
return result;
}, {});
var result = Object.keys(step1).map(category => ({category, items: step1[category]}));
Which babel converts to
var step1 = items.reduce(function (result, _ref) {
var category = _ref.category,
id = _ref.id,
content = _ref.content;
result[category] = result[category] || [];
result[category].push({ id: id, content: content });
return result;
}, {});
var result = Object.keys(step1).map(function (category) {
return { category: category, items: step1[category] };
});
So I just solved the question with the following code (jsfiddle):
// Items
// var items = []
// Create an empty object, used to store the different categories.
var temporaryObject = {}
// Scan for each of the objects in the `items` array.
items.forEach((item) =>
{
// Create a category in the teporary object if the category
// hasn't been created.
if(typeof temporaryObject[item.category] === "undefined")
temporaryObject[item.category] = []
// Push the item to the its category of the `temporaryObject`.
temporaryObject[item.category].push({
id : item.id,
content: item.content
})
})
// Create a empty array used to stores the sorted, grouped items.
var newItems = []
// Scan for each of the category in the `temporaryObject`
for(var category in temporaryObject)
{
// Push the new category in the `newItems` array.
newItems.push({
category: category,
items : []
})
// Get the last category index of the `newItems` array,
// so we can push the related data to the related category.
var lastItem = newItems.length - 1
// Scan for the related category in the `temporaryObject` object.
temporaryObject[category].forEach((item) =>
{
// Push the related data to the related category of the `newItems` array.
newItems[lastItem].items.push(item)
})
}
// Prints the sorted, grouped result.
console.log(newItems)
Related
I am attempting to group an array elements ( containing orders details ).
here is my array structure :
[{"id":"myid","base":{"brands":["KI", "SA"],"country":"BG","status":"new"}},{"id":"DEC-00500331","base":{"brands":["DEC"],"country":"UK","status":"new"},"psp":{"name":"adyen","status":"paid"}}]
An order is related to a country website, and can contain one or more brands. for example in one order I can have and item from brand1 and an item from brand2.
I need to group these orders, by country and brand so I can have a consolidated array or object.
I can group by country easily :
let groupedDataByCountryAndBrand = _.groupBy(orders.value, 'base.country')
Object.keys(groupedDataByCountryAndBrand).forEach(key => {
table.push(
{
country : key, //to be reviewd : for the two brands or more in one order
new : groupedDataByCountryAndBrand[key].filter( order => (order.base.status === SFCC_STATUS.new
|| SFCC_STATUS.open
|| SFCC_STATUS.completed )).length
})
})
Here is the result :
Unfortunatly this is not working for me. I need to group the orders by country and brand so that I can count the newly created orders for each brand by country.
Result I am expecting is something like this :
{
"country" : "FR",
"brand": "adidas",
"pending": 4
"new" : 3,
"an other status": 5
}
Do you have any idea how I can achieve this ?
I am using lodash with vue component.
Thanks.
Here is what you are looking for, without using of any additional libraries:
const data = [{"id":"myid","base":{"orderNumber":"0500332","marketPlaceOrderCode":"","creationDate":"2022-06-14T10:49:10Z","source":"sfcc","brands":["KI", "SA"],"country":"BG","status":"new","totalEuro":12,"currency":"BGN","units":1,"coupons":null,"shipping":{"id":"BG01","name":"Speedy COD","status":"not_shipped"}},"psp":{"name":"payu","method":null,"status":null},"tms":null},{"id":"DEC-00500331","base":{"orderNumber":"id2","marketPlaceOrderCode":"","creationDate":"2022-06-14T10:41:29Z","source":"sfcc","brands":["DEC"],"country":"UK","status":"new","totalEuro":57,"currency":"GBP","units":1,"coupons":null,"shipping":{"id":"ECA_DPD_ST","name":"Standard shipping","status":"not_shipped"}},"psp":{"name":"adyen","method":null,"status":"paid"},"tms":null}];
const rawResult = normalizeData(data);
console.log(makeItReadable(rawResult));
function normalizeData(data) {
const result = {};
data.forEach((order) => {
const orderData = order.base;
// add country to result (if not exists)
if (!result[orderData.country]) {
result[orderData.country] = {};
}
orderData.brands.forEach((brand) => {
// add brand to exact country (if not exists)
if (!result[orderData.country][brand]) {
result[orderData.country][brand] = {};
}
// add status to exact brand and country (if not exists)
if (!result[orderData.country][brand][orderData.status]) {
result[orderData.country][brand][orderData.status] = 0;
}
// increment status count
++result[orderData.country][brand][orderData.status];
});
});
return result;
}
function makeItReadable(rawData) {
const readableResult = [];
Object.keys(rawData).map((country) => {
Object.keys(rawData[country]).map((brand) => {
readableResult.push({country, brand, ...rawData[country][brand]});
});
});
return readableResult;
}
This code will give you the following result:
[
{ country: 'BG', brand: 'KI', new: 1 },
{ country: 'BG', brand: 'SA', new: 1 },
{ country: 'UK', brand: 'DEC', new: 1 }
]
I created an empty array in localStorage
localStorage.setItem('items', JSON.stringify([]))
and then fetching that empty array like this :
let fetchedItems = JSON.parse(localStorage.getItem('items'));
After fetching the Array I want to append some objects in the same.
Array of Objects
let objects = [
{
id: '37f60b13-bb3a-4919-beff-239207745343',
body: '1',
},
{
id: '26c5b0fa-b15f-4a50-9a56-5880727a8020',
body: '2',
},
{
id: '37f60b13-bb3a-4919-beff-239207745343',
body: '1',
},
];
The first and last object have same id
Right now what I am doing is, as I don't want to save or append duplicate objects (by id key) in array/localstorage:
function saveItemsInLocalStorage(item) {
let items;
if (localStorage.getItem('items') === null) {
items = [];
} else {
items = JSON.parse(localStorage.getItem('items'));
}
items.push({
id: item.id,
body: item.body,
});
localStorage.setItem('items', JSON.stringify(items));
}
objects.forEach((object) => {
fetchedItems.forEach((fetchedItem) => {
if (fetchedItem.id !== object.id) {
saveItemsInLocalStorage(object)
}
});
});
The above code is not working. I have also tried reduce method.
Note initially array is empty
Let us take an example and try understanding , how you can do it with your code :
let obj = {name:"user",id:1};
let arr = [{name:"user",id:2},{name:"user",id:3}];
let present = false ;
arr.map(val=>{
if(JSON.stringify( {...val})===JSON.stringify({...obj}) )
present = true ;
})
if(present)console.log("The object is present")
else console.log("The object is not present");
I'm having two data arrays which are coming from API and sample arrays would be like this
Array 1
[
{userId: 1
description: "Student"
imagePath: "test.png"
status: 1
}]
Array 2
[
{id: 85
accountName: "Rahul"
accountNumber: "11145678"
}
]
In my reactnative app view there's search bar and user should be able to search from these two arrays. So I merged these two arrays into one using
this.searchArray =this.filterArray[0].concat(this.filterArray[1])
So, my searchArray is a single array with Array1 and Array2 data. sample below
[
{userId: 1
description: "Student"
imagePath: "test.png"
status: 1
},
{id: 85
accountName: "Rahul"
accountNumber: "11145678"
}]
My search function is below (I need to search from account number or description)
//Search Filter
searchFilter =searchText=>{
const searchTextData = searchText.toUpperCase();
const userSearch = this.searchArray.filter(item => {
const itemData = `${item.description && item.description.toUpperCase()} ${item. accountName && item.accountName.toUpperCase()}`;
return itemData.indexOf(searchTextData) > -1;
});
}
The search functionality is not working with accountName. It's not getting any results. But if I remove ${item. accountName && item.accountName.toUpperCase()} , then it's working showing data with description. But I need to filter from both
In your array one object can have description or accountNumber so do a check if that exists include it in the itemData variable.
Try doing this
searchFilter =searchText=>{
const searchTextData = searchText.toUpperCase();
const userSearch = this.searchArray.filter(item => {
const itemData = `${item.hasOwnProperty('description'))?item.description.toUpperCase():''} ${item.hasOwnProperty('accountNumber')?item.accountNumber:''}`;
return itemData.indexOf(searchTextData) > -1;
});
}
First merge the two objects into one:
Object.keys(arr2[0]).forEach(key => {
arr1[0][key] = arr2[0][key]
})
Then create the search function:
function searchObject(obj, value){
return Object.keys(obj).some(key => {
return obj[key] === value
})
}
let arr1=[{userId:1,description:"Student",imagePath:"test.png",status:1}],arr2=[{id:85,accountName:"Rahul",accountNumber:"11145678"}];
Object.keys(arr2[0]).forEach(key => {
arr1[0][key] = arr2[0][key]
})
function searchObject(obj, prop, value){
return obj[prop] === value
}
console.log(searchObject(arr1[0], "accountName", "asdf"))
console.log(searchObject(arr1[0], "accountName", "Rahul"))
How to add uniqueId field in below JSON. This array has large number of data and needs to dynamic unique identifier on existing array.
[{"title":"Accompanying"},{"title":"Chamber music"},{"title":"Church
music"}......]
so, this should look as follow:
[{"title":"Accompanying", "uniqueId": 1},{"title":"Chamber music", "uniqueId": 2}..]
uniqueId- type, number or guid.
Note: don't know the "title" or what other fields could be, so, could not map the fields by name.
I would go for a simple for loop
let myArray = [{"title":"Accompanying"},{"title":"Chamber music"},{"title":"Church music"}];
let i = 0, ln = myArray.length;
for (i;i<ln;i++){
myArray[i].uniqueId = i+1;
}
console.log(myArray);
If this is a one time thing you could do the following:
const newArray = oldArray.map((x, i) => ({
// If the object is dynamic you can spread it out here and add the ID
...x,
// Use the items index in the array as a unique key
uniqueId: i,
}));
If you want to use a guid generator instead (I'd recommend that) just replace i with whatever you use to generate a GUID and ensure that any time you add to the collection you generate a new GUID for the data.
const newArray = oldArray.map((x) => ({ ...x, uniqueId: generateGuid() }));
const yourDynamicObjects = [
{
title: 'A title',
author: 'A. Author'
},
{
foo: 'bar',
},
{
quotient: 2,
irrational: Math.sqrt(2)
}
];
const updatedData = yourDynamicObjects.map((x, i) => ({ ...x, uniqueId: i, }));
console.log(updatedData);
You can use map & in it's call back function use the index parameter to create uniqueId
item.title is not known actually as its dynamic array and so, could
not map with particular field names
In this case use Object.keys to get an array of all the keys . Then loop over it and add the key to a new object
let k = [{
"title": "Accompanying"
}, {
"title": "Chamber music"
}, {
"title": "Church"
}]
let getArrayKey = Object.keys(k[0]);
let n = k.map(function(item, index) {
let obj = {};
getArrayKey.forEach(function(elem) {
obj[elem] = item[elem];
})
obj.uniqueId = index + 1
return obj;
});
console.log(n)
Also you can use spread operator
let k = [{
"title": "Accompanying"
}, {
"title": "Chamber music"
}, {
"title": "Church"
}]
let n = k.map(function(item, index) {
return Object.assign({}, { ...item,
uniqueId: index + 1
})
});
console.log(n)
Trying to transform an object of objects:
var items: {
item_a: {
state: 'item_a status'
},
item_b: {
state: 'item_b status'
}
};
into an array of objects, whilst adding a new array element to the object (the object key):
var items = [{
name: 'item_a',
state: 'item_a status'
}, {
name: 'item_b',
state: 'item_b status'
}];
My naive attempt, which works, is thus:
var arrayOfItems = [];
for(var x in items){
var itemObj = {
name: x
};
for(var y in items[x]){
itemObj[y] = items[x][y];
}
arrayOfItems.push(itemObj);
}
I'm wondering if there's a cleaner way to do this, using maybe something Underscore/LoDash?
I would use map() for this:
_.map(items, function(item, key) {
return _.assign({ name: key }, item);
});
// →
// [
// {
// name: 'item_a',
// state: 'item_a status'
// },
// {
// name: 'item_b',
// state: 'item_b status'
// }
// ]
Since map() always returns an array, you're halfway there. You just need the callback to generate your array items. You can use the assign() function to setup your new name property, and then add the rest of the properties.
var newItems = _.map(items, function(item, key){
item.name = key;
return item;
});
console.log(newItems);