Related
I'm trying to group an array of objects. The array should be grouped following this quote:
Group by type respecting the sequence.
Array I wish to group
var arrayObj = [
{ "type": "user", "text": "user1" },
{ "type": "user", "text": "user2" },
{ "type": "user", "text": "user3" },
{ "type": "clerk", "text": "clerk1" },
{ "type": "user", "text": "user4" },
{ "type": "clerk", "text": "clerk2" },
{ "type": "clerk", "text": "clerk3" },
{ "type": "user", "text": "user5" },
{ "type": "user", "text": "user6" }
];
The way I want it to be grouped:
var newArray = [
[
{type: "user", text: "user1"},
{type: "user", text: "user2"},
{type: "user", text: "user3"}
],
[
{type: "clerk", text: "clerk1"}
],
[
{type: "user", text: "user4"}
],
[
{type: "clerk", text: "clerk2"},
{type: "clerk", text: "clerk3"}
],
[
{type: "user", text: "user5"},
{type: "user", text: "user6"}
]
];
What i tried:
I'm trying to use a filter, but without success since it even groups, but it groups all that are of the same type without respecting the sequence I want (from the array above);
var arrayObj = [
{ "type": "user", "text": "user1" },
{ "type": "user", "text": "user2" },
{ "type": "user", "text": "user3" },
{ "type": "clerk", "text": "clerk1" },
{ "type": "user", "text": "user4" },
{ "type": "clerk", "text": "clerk2" },
{ "type": "clerk", "text": "clerk3" },
{ "type": "user", "text": "user5" },
{ "type": "user", "text": "user6" }
];
var newArray = [];
newArray.push(filtrarArray(arrayObj, 'clerk'));
newArray.push(filtrarArray(arrayObj, 'user'));
console.log(newArray);
function filtrarArray(array, type) {
return array.filter(function (val) {
return val.type === type;
});
}
The snippet below first sorts the array by type, which then makes it easy to loop through and group. Let me know if this solves your problem :)
EDIT
Just realized you didn't need sorting, so I commented the sort function out, but it's always there to be uncommented if you change your mind :)
const arrayObj = [
{ type: 'user', text: 'user1' },
{ type: 'user', text: 'user2' },
{ type: 'user', text: 'user3' },
{ type: 'clerk', text: 'clerk1' },
{ type: 'user', text: 'user4' },
{ type: 'clerk', text: 'clerk2' },
{ type: 'clerk', text: 'clerk3' },
{ type: 'user', text: 'user5' },
{ type: 'user', text: 'user6' },
];
const group = ar =>
ar
// .sort((a, b) => (a.type < b.type ? -1 : 1))
.reduce((newAr, obj, i) => {
if (0 === i) return [[obj]];
if (obj.type === newAr[newAr.length - 1][0].type)
return newAr[newAr.length - 1].push(obj), newAr;
return [...newAr, [obj]];
}, []);
const groupedAr = group(arrayObj);
console.log(groupedAr);
function groupConsecutive(arrayObj) {
if (arrayObj.length === 0) {
return [];
}
let matchedTypesIndex = 0;
let newArray = [
[
arrayObj[0]
]
];
let currentType = arrayObj[0]["type"];
let i = 1;
while (i < arrayObj.length) {
if (arrayObj[i]["type"] === currentType) {
newArray[matchedTypesIndex].push(arrayObj[i]);
} else {
currentType = arrayObj[i]["type"];
newArray.push([]);
matchedTypesIndex++;
newArray[matchedTypesIndex].push(arrayObj[i]);
}
i++;
}
return newArray;
}
This is probably not best pure solution but works as you need.
var arrayObj = [
{ "type": "user", "text": "user1" },
{ "type": "user", "text": "user2" },
{ "type": "user", "text": "user3" },
{ "type": "clerk", "text": "clerk1" },
{ "type": "user", "text": "user4" },
{ "type": "clerk", "text": "clerk2" },
{ "type": "clerk", "text": "clerk3" },
{ "type": "user", "text": "user5" },
{ "type": "user", "text": "user6" }
];
let lastType;
let arr = [];
let arrIndex = -1;
arrayObj.forEach(obj => {
if(obj.type == lastType) { // add item into last group array by index
arr[arrIndex].push(obj);
}
else { // or add new group array
lastType = obj.type;
arrIndex++;
arr.push([obj]);
}
})
console.log(arr);
See This solution it will work
var arrayObj = [
{ type: "user", text: "user1" },
{ type: "user", text: "user2" },
{ type: "user", text: "user3" },
{ type: "clerk", text: "clerk1" },
{ type: "user", text: "user4" },
{ type: "clerk", text: "clerk2" },
{ type: "clerk", text: "clerk3" },
{ type: "user", text: "user5" },
{ type: "user", text: "user6" },
];
let typeNow = arrayObj[0].type;
let res = [];
let resultArray = [];
arrayObj.forEach((obj, i) => {
if (obj.type == typeNow) {
resultArray.push(obj);
} else {
resultArray = [obj];
res.push(resultArray);
typeNow = obj.type;
}
if (i == arrayObj.length - 1) res.push(resultArray);
});
console.log(res);
This is best solution can i have
It seem unordred because of Browser auto order but if you try in js file it will work and ordred
I'm responding with another way I found to solve my problem. This is just one more way I decided to comment.
Let's go:
I'm traversing the arrayObjects array using the appropriate loop for arrays for...of and then checking if the variable I set for arrayObjects (loopArrObj) has a different value of type of the variable (typeValue), if it is inserted at the end of the new array (grouping) using the array method push an empty array and then assign the value of the loopArrObj(Ie, there will be in the array grouping array empty only for the values that are different).
So far so good, we have the first empty array. Next I'm defining this empty array with the push method the loopArrObj object in question, then we get the value through the console. I'm removing 1 from grouping.lengh so the loop assigns from 0 and not 1.
var arrayObjects = [
{ "type": "user", "text": "user1" },
{ "type": "user", "text": "user2" },
{ "type": "user", "text": "user3" },
{ "type": "clerk", "text": "clerk1" },
{ "type": "user", "text": "user4" },
{ "type": "clerk", "text": "clerk2" },
{ "type": "clerk", "text": "clerk3" },
{ "type": "user", "text": "user5" },
{ "type": "user", "text": "user6" }
];
let typeValue,
grouping = [],
loopArrObj;
for (loopArrObj of arrayObjects) {
if (loopArrObj.type !== typeValue) {
grouping.push([]);
typeValue = loopArrObj.type;
}
grouping[grouping.length - 1].push(loopArrObj);
}
console.log(grouping);
I have below data from my API call and I am working with reduce function to set data as per my requirement. But not able to produce it, please check below code and required output. Also check the function I am trying and suggest me way to create the response.
API Response:
let cmpRecords = {
"status": "success",
"message": "Record Fetched Successfully",
"data": [
{
"_id": "6098ff60a8e9ee2c7c116d6e",
"record": {
"creatorName": "ABC",
"modifierName": ""
},
"is_deleted": "0"
},
{
"_id": "6098ff60a8e9ee2c7c116d6e",
"record": {
"creatorName": "ABC",
"modifierName": ""
},
"is_deleted": "0"
},
{
"_id": "6098ff60a8e9ee2c7c116d6z",
"record": {
"creatorName": "XYZ",
"modifierName": ""
},
"is_deleted": "0"
},
...
]
}
Required Output ::
{
"status": "success",
"message": "Record Fetched Successfully",
"data": [
{
"name": "ABC",
"record": [
{
"_id": "6098ff60a8e9ee2c7c116d6e",
"record": {
"creatorName": "ABC",
"modifierName": ""
},
"is_deleted": "0"
},
{
"_id": "6098ff60a8e9ee2c7c116d6e",
"record": {
"creatorName": "ABC",
"modifierName": ""
},
"is_deleted": "0"
}
]
},
{
"name": "XYZ",
"record": [
{
"_id": "6098ff60a8e9ee2c7c116d6z",
"record": {
"creatorName": "XYZ",
"modifierName": ""
},
"is_deleted": "0"
}
]
}
]
}
As I want to seperate record of same user, with key and value & key and object I used reduce function for this
group = cmpRecords.reduce((r, a) => {
let name = a.record.creatorName;
let record = a;
r[name] = [...r[name] || [], record];
return r;
}, {});
This responds with
"data": [
"ABC":[
{
"_id": "6098ff60a8e9ee2c7c116d6e",
"record": {
"creatorName": "ABC",
"modifierName": ""
},
"is_deleted": "0"
},
...
]
]
I tried other ways but not getting required response.
You can use Array.reduce() to group your records by name, the output here should be what you require:
const cmpRecords = { "status": "success", "message": "Record Fetched Successfully", "data": [ { "_id": "6098ff60a8e9ee2c7c116d6e", "record": { "creatorName": "ABC", "modifierName": "" }, "is_deleted": "0" }, { "_id": "6098ff60a8e9ee2c7c116d6e", "record": { "creatorName": "ABC", "modifierName": "" }, "is_deleted": "0" }, { "_id": "6098ff60a8e9ee2c7c116d6z", "record": { "creatorName": "XYZ", "modifierName": "" }, "is_deleted": "0" }, ] }
const output = {
...cmpRecords,
data: Object.values(cmpRecords.data.reduce((acc, cur) => {
acc[cur.record.creatorName] = acc[cur.record.creatorName] || { name: cur.record.creatorName, record: [] };
acc[cur.record.creatorName].record.push(cur);
return acc;
}, {}))
}
console.log('Output:', output)
I have a JavaScript array with the following format:
[
{
"header": true,
"id": "0",
"name": "dairy",
},
{
"category": "dairy",
"header": false,
"id": "-LSlje6ESGALGpckMhb7",
"name": "milk",
},
{
"category": "dairy",
"header": false,
"id": "-LSm9EpFg5DhW036aUle",
"name": "cheese",
},
{
"header": true,
"id": "3",
"name": "dessert",
},
{
"category": "dessert",
"header": false,
"id": "-LSm9MLZkrnvtPySw5U6",
"name": "cake",
},
{
"category": "dessert",
"header": false,
"id": "-LSmAQ0rdDLrpz0TSPuD",
"name": "pie",
},
{
"header": true,
"id": "6",
"name": "fruit",
},
{
"category": "fruit",
"header": false,
"id": "-LSlazVIGAKLakxAIa8G",
"name": "apple",
},
{
"category": "fruit",
"header": false,
"id": "-LSlb5GH6xZz-DpNVS22",
"name": "pear",
},
{
"category": "fruit",
"header": false,
"id": "-LSwWJldY1nxQrotyv-V",
"name": "strawberry",
},
{
"header": true,
"id": "10",
"name": "meat",
},
{
"category": "meat",
"header": false,
"id": "-LSljXQzfXthJbOA54Ah",
"name": "fish",
},
{
"category": "meat",
"header": false,
"id": "-LSmA2-R9pOY8abAUyST",
"name": "steak",
},
{
"category": "meat",
"header": false,
"id": "-LSmAJ4J4gIfVQ8sgPDa",
"name": "pork",
},
]
What I am trying to do, is map through this array, and transform it to the following format:
[
{
title: nameOfFirstHeader,
data: items.slice(indexOfFirstHeader, indexOfSecondHeader),
},
{
title: nameOfSecondHeader,
data: items.slice(indexOfSecondHeader, indexOfThirdHeader),
},
{
title: nameOfThirdHeader,
data: items.slice(indexOfThirdHeader, indexOfFourthHeader),
},...and so on
]
So basically there will be an object section for each 'header' that is found in the original array. Each object section data property will contain the items found between the first header and the second header, and so on, until there are no more headers. I really can't wrap my head around how I can do this. Here is a reference to the the module I am using: https://github.com/saleel/react-native-super-grid#sectiongrid-example
Thanks!
I think this may be what you're trying to accomplish...
var grouped = items.reduce((acc,obj)=>{
let {header, name} = obj;
if (header) return [...acc, { title:name, data:[] }] // either first matching header or new match. Add fresh 'header' object
if (!acc.length) return acc; //not header and none have passed. Do nothing
let allButLast = acc.slice(0, acc.length-1),
lastElem = acc[acc.length-1]; // not a header, but there is an existing match. Add it to last match's data array
return [
...allButLast,
{
...lastElem,
data:[...lastElem.data, obj]
}
]
},[])
but it seems unreliable to trust the order of an array for this purpose. It would probably be more reliable to match by isHeader.name === notHeader.category to be less presumptive about the order of data you're iterating over. Like this...
var grouped = items.reduce((acc,obj)=>{
let {header, name, category} = obj;
if (header) return [...acc, { title:name, data:[] }];
if (!acc.length) return acc;
return acc.map((elem)=>{
if (elem.title !== category) return elem;
return {
...elem,
data: [ ...elem.data, obj]
};
})
},[])
I think you can probably do something like
const data = [];
let activeIndexForData = -1;
for(let i = 0; i < dataToSort.length -1; i++) {
if(dataToSort[i].header) {
activeIndexForData++;
}
if(data.length < activeIndexForData - 1) {
data.push({ title: dataToSort[i].name, data# []})
}
else {
data[activeIndexForData].data.push({ title: dataToSort[i].name, data: [])
}
}
Check for the decimal id and group them accordingly.
Below are the sample and recommended JSON's
Sample JSON
{
"results": [
{
"name": "Download",
"id": "1.1.1"
},
{
"name": "Download",
"id": "1.2"
},
{
"name": "Download",
"id": "1.3.2"
},
{
"name": "Download",
"id": "2"
},
{
"name": "Download",
"id": "2.3"
},
{
"name": "Download",
"id": "3.2"
},
{
"name": "Download",
"id": "3.5"
},
{
"name": "Download",
"id": "4.2"
}
]
}
Would like to iterate and Re-structure the above JSON into below recommended format.
Logic: Should check the id(with and without decimals) and group them based on the number.
For Example:
1, 1.1, 1.2.3, 1.4.5 => data1: [{id: 1},{id: 1.1}....]
2, 2.3, 2.3.4 => data2: [{id: 2},{id: 2.3}....]
3, 3.1 => data3: [{id: 3},{id: 3.1}]
Recommended JSON
{
"results": [
{
"data1": [
{
"name": "Download",
"id": "1.1.1"
},
{
"name": "Download",
"id": "1.2"
},
{
"name": "Download",
"id": "1.3.2"
}
]
},
{
"data2": [
{
"name": "Download",
"id": "2"
},
{
"name": "Download",
"id": "2.3"
}
]
},
{
"data3": [
{
"name": "Download",
"id": "3.2"
},
{
"name": "Download",
"id": "3.5"
}
]
},
{
"data4": [
{
"name": "Download",
"id": "4.2"
}
]
}
]
}
I have tried the below solution but it doesn't group the object
var formatedJSON = [];
results.map(function(d,i) {
formatedJSON.push({
[data+i]: d
})
});
Thanks in advance.
You can use reduce like this. The idea is to create a key-value pair for each data1, data2 etc so that values in this object are the values you need in the final array. Then use Object.values to get those as an array.
const sampleJson = {"results":[{"name":"Download","id":"1.1.1"},{"name":"Download","id":"1.2"},{"name":"Download","id":"1.3.2"},{"name":"Download","id":"2"},{"name":"Download","id":"2.3"},{"name":"Download","id":"3.2"},{"name":"Download","id":"3.5"},{"name":"Download","id":"4.2"}]}
const grouped = sampleJson.results.reduce((a, v) => {
const key = `data${parseInt(v.id)}`;
(a[key] = a[key] || {[key]: []})[key].push(v);
return a;
},{});
console.log({results: Object.values(grouped)})
One liner / Code-golf:
let s={"results":[{"name":"Download","id":"1.1.1"},{"name":"Download","id":"1.2"},{"name":"Download","id":"1.3.2"},{"name":"Download","id":"2"},{"name":"Download","id":"2.3"},{"name":"Download","id":"3.2"},{"name":"Download","id":"3.5"},{"name":"Download","id":"4.2"}]},k;
console.log({results:Object.values(s.results.reduce((a,v)=>(k=`data${parseInt(v.id)}`,(a[k] = a[k]||{[k]:[]})[k].push(v),a),{}))})
Here you go:
var data = {
"results": [
{
"name": "Download",
"id": "1.1.1"
},
{
"name": "Download",
"id": "1.2"
},
{
"name": "Download",
"id": "1.3.2"
},
{
"name": "Download",
"id": "2"
},
{
"name": "Download",
"id": "2.3"
},
{
"name": "Download",
"id": "3.2"
},
{
"name": "Download",
"id": "3.5"
},
{
"name": "Download",
"id": "4.2"
}
]
};
let newSet = new Set();
data.results.forEach(e => {
let key = e.id.substring(0, e.id.indexOf('.'));
console.log(key);
if (newSet.has(key) == false) {
newSet.add(key);
newSet[key] = [];
}
newSet[key].push(e.id);
});
console.log(newSet);
Here's how you'd do it:
var data = {
"results": [
{
"name": "Download",
"id": "1.1.1"
},
{
"name": "Download",
"id": "1.2"
},
{
"name": "Download",
"id": "1.3.2"
},
{
"name": "Download",
"id": "2"
},
{
"name": "Download",
"id": "2.3"
},
{
"name": "Download",
"id": "3.2"
},
{
"name": "Download",
"id": "3.5"
},
{
"name": "Download",
"id": "4.2"
}
]
};
var newData = {
"results": {}
};
data.results.forEach(item => {
var num = item.id.slice(0, 1);
if (newData.results["data" + num]) {
newData.results["data" + num].push(item);
} else {
newData.results["data" + num] = [item];
}
})
data = newData;
console.log(data);
What this does is it iterates through each item in results, gets the number at the front of this item's id, and checks if an array of the name data-{num} exists. If the array exists, it's pushed. If it doesn't exist, it's created with the item.
let input = getInput();
let output = input.reduce((acc, curr)=>{
let {id} = curr;
let majorVersion = 'name' + id.split('.')[0];
if(!acc[majorVersion]) acc[majorVersion]= [];
acc[majorVersion].push(curr);
return acc;
},{})
console.log(output)
function getInput(){
return [
{
"name": "Download",
"id": "1.1.1"
},
{
"name": "Download",
"id": "1.2"
},
{
"name": "Download",
"id": "1.3.2"
},
{
"name": "Download",
"id": "2"
},
{
"name": "Download",
"id": "2.3"
},
{
"name": "Download",
"id": "3.2"
},
{
"name": "Download",
"id": "3.5"
},
{
"name": "Download",
"id": "4.2"
}
]
}
One solution with RegEx for finer control as it would differentiate easily between 1 and 11.
Also this will make sure that even if the same version comes in end(say 1.9 in end) it will put it back in data1.
let newArr2 = ({ results }) =>
results.reduce((acc, item) => {
let key = "data" + /^(\d+)\.?.*/.exec(item.id)[1];
let found = acc.find(i => key in i);
found ? found[key].push(item) : acc.push({ [key]: [item] });
return acc;
}, []);
This is my json:
{
"senderName": "ifelse",
"message": "Hi",
"groups": [
{
"id": 14,
"groupname": "Angular",
"contactgroups": [
{
"id": 1,
"contact": {
"id": 1,
"gsm": "123456789"
}
},
{
"id": 3,
"contact": {
"id": 2,
"gsm": "111111111"
}
}],
"select": true
}],
"draftData": {
"contacts": [
]
}
}
How to make the above json into:
[{phoneno: 123456789; sender: ifelse ; message: Hi},{phoneno: 11111111; sender: ifelse ; message: Hi}]
I want to take phoneno data from gsm object key
Which is best method to do this? for or forEach or anyother?
I guess, this is what you want. Use map to convert contactgroups to new array with phoneno.
var data = {
"senderName": "ifelse",
"message": "Hi",
"groups": [{
"id": 14,
"groupname": "Angular",
"contactgroups": [{
"id": 1,
"contact": {
"id": 1,
"gsm": "123456789"
}
},
{
"id": 3,
"contact": {
"id": 2,
"gsm": "111111111"
}
}
],
"select": true
}],
"draftData": {
"contacts": []
}
}
var result = data.groups[0].contactgroups.map(i => {
return {
phoneno: i.contact.gsm,
sender: data.senderName,
message: data.message
}
})
console.log(result);