I want to change the structure of my array - javascript

I need to modify a data which is coming from API. The data is coming in the form of array of objects.
const crosses = [
{
fatherLineId: 8,
fatherLineName: "2ART18-0008",
id: 54,
motherLineId: 5,
motherLineName: "2ART18-0005",
},
{
fatherLineId: 3
fatherLineName: "2ART18-0003",
id: 55,
motherLineId: 5,
motherLineName: "2ART18-0005",
}
]
I want my data to be restructured in the form of:
const resultantArr = [
{
enteryNumber: 1,
ParentName: "2ART18-0008"
},
{
entryNumber: 2,
ParentName: "2ART18-0005",
},
{
entryNumber: 3,
ParentName: "2ART18-0003"
},
and so on ...
];
Here the parentName property will have motherLineName values and fatherLineName values in the order.

When you get the result of the api call, loop through it and map the data toy our custom object, I can't provide a complete example based on your question but something like this:
You may also need to parse the apiresult into json using JSON.parse()
var resultantArr = [];
for(var i = 0; i < apiresult.length; i++)
{
resultantArr.push({"enteryNumber" : i + 1 , "ParentName" : apiresult[i].fatherLineName });
}

Loop over the array and push two separate objects into an output array. And keep a record of each object entryname that you increment by two at the end of each iteration.
const crosses=[{fatherLineId:8,fatherLineName:"2ART18-0008",id:54,motherLineId:5,motherLineName:"2ART18-0005"},{fatherLineId:3,fatherLineName:"2ART18-0003",id:55,motherLineId:5,motherLineName:"2ART18-0005"}];
const out = [];
let count = 1;
crosses.forEach(obj => {
const { fatherLineName, motherLineName } = obj;
out.push({
entryNumber: count,
parentName: fatherLineName
});
out.push({
entryNumber: count + 1,
parentName: motherLineName
});
count = count + 2;
});
console.log(out);

Hope it helps you... 🙂
const crosses = [
{
fatherLineId: 8,
fatherLineName: "2ART18-0008",
id: 54,
motherLineId: 5,
motherLineName: "2ART18-0005",
},
{
fatherLineId: 3,
fatherLineName: "2ART18-0003",
id: 55,
motherLineId: 5,
motherLineName: "2ART18-0005",
}
];
var result = [];
var count = 1;
crosses.forEach(cross => {
result.push({
parentName: cross.fatherLineName,
entryNumber: count++,
}),
result.push({ parentName: cross.motherLineName,
entryNumber: count++,
})
});
result

Related

re-organizing array of objects

So I have an array of objects that contain information for different activities in different projects.
It looks something like this
const input = [
{
Project: 1,
ID: "1-1",
},
{
Project: 1,
ID: "1-2",
},
{
Project: 2,
ID: "2-1",
},
];
From this, I would like to go to this
output = [{
Project: 1,
ID1: 1 - 1,
ID2: 1 - 2,
},
{
Project: 1,
ID1: 2 - 1,
},
];
Here's what I have so far:
let currentProject = ''
let output = []
for (const e of input) {
let counter
let outputObj = {}
if (currentProject !== e.Project) {
output.push(outputObj)
counter = 1
outputObj = {}
outputObj.projectNum = e.Project
currentProject = e.Project
}
if (currentProject == e.Project) {
outputObj['ID' + counter] = e.ID
counter++
}
}
here's what I'm getting back:
output = [{
Project: 1,
ID1: 1 - 1
},
{
Project: 1,
ID1: 2 - 1
}
]
I'm not sure what the issue is, tried several times to fix it.
Could someone please help me get over the edge?
Any help will be greatly appreciated.
You can achieve this using reduce, Object.keys
const input = [{
Project: 1,
ID: "1-1",
},
{
Project: 1,
ID: "1-2",
},
{
Project: 2,
ID: "2-1",
},
];
const result = input.reduce((acc, curr) => {
const { Project, ID } = curr;
const obj = acc.find((el) => el.Project === Project);
if (obj) {
const length = Object.keys(obj).length;
obj[`ID${length}`] = ID;
} else {
acc.push({ Project, [`ID${1}`]: ID });
}
return acc;
}, []);
console.log(result);
You can try this.
const input=[{Project:1,ID:"1-1",},{Project:1,ID:"1-2",},{Project:2,ID:"2-1"}];
let temp = {};
input.map(v=>(temp[v.Project] ??= []).push(v.ID));
let output = Object.keys(temp).map(k=>{
let json = {Project:k};
temp[k].map((v,k)=>json['ID'+(Number(k+1))]=v);
return json;
});
console.log(output);
you will get the result.
[
{ Project: '1', ID1: '1-1', ID2: '1-2' },
{ Project: '2', ID1: '2-1' }
]
The way you intended to implement this assumes every project from same id comes sequentially grouped.
While #decpk answer deals with with a linear search, for performance reasons I would rather first use a dictionary and then convert to an array, AND also keep track of id quantities using a field n.
const input = [
{
Project: 1,
ID: "1-1",
},
{
Project: 1,
ID: "1-2",
},
{
Project: 2,
ID: "2-1",
},
];
const projects = {}
for (const e of input) {
let pid = e.Project
let project = projects[pid]
//First time seeing this project
if (!project) {
projects[pid] = { Project: pid, n: 1, ID1: e.ID }
}
//insert more ID
else {
project.n += 1
project[`ID${project.n}`] = e.ID
}
}
//And now converting the object to array, removing the 'n' field
const output = Object.keys(projects).map(pid => {
const obj = projects[pid]
delete obj.n
obj.Project = pid
return obj
})
You can try this way - O(n) time complexity
Using reduce to aggregate data.
Using logical nullish assignment only assigns if acc[Project] is nullish (null or undefined).
Define each additional key-value pair like:
const number = Object.keys(acc[Project]).length; // Define key format by number of existing property.
const key = `ID${number}`;
instead of using count variable.
const input=[{Project:1,ID:"1-1",},{Project:1,ID:"1-2",},{Project:2,ID:"2-1",}];
const output = input.reduce((acc, {Project, ID}) =>
{
acc[Project] ??= {Project}; // Get exist object or create new one
const number = Object.keys(acc[Project]).length; // Define key format by number of existing property.
const key = `ID${number}`;
acc[Project][key] = ID;
return acc;
}, {});
console.log(Object.values(output));
Output:
[
{
"Project": 1,
"ID1": "1-1",
"ID2": "1-2"
},
{
"Project": 2,
"ID1": "2-1"
}
]

How to invert the structure of nested array of objects in Javascript?

I currently have an array that has the following structure:
data = [
{
time: 100,
info: [{
name: "thing1",
count: 3
}, {
name: "thing2",
count: 2
}, {
}]
},
{
time: 1000,
info: [{
name: "thing1",
count: 7
}, {
name: "thing2",
count: 0
}, {
}]
}
];
But I would like to restructure the array to get something like this:
data = [
{
name: "thing1",
info: [{
time: 100,
count: 3
}, {
time: 1000,
count: 7
}, {
}]
},
{
name: "thing2",
info: [{
time: 100,
count: 2
}, {
time: 1000,
count: 0
}, {
}]
}
];
So basically the key would have to be switched from time to name, but the question is how. From other posts I have gathered that using the map function might work, but since other posts had examples to and from different structures I am still not sure how to use this.
There are a number of ways to achieve this however, the key idea will be to perform a nested looping of both data items and their (nested) info items. Doing that allows your algorithm to "visit" and "map" each piece of input data, to a corresponding value in the resulting array.
One way to express that would be to use nested calls to Array#reduce() to first obtaining a mapping of:
name -> {time,count}
That resulting mapping would then be passed to a call to Object.values() to transform the values of that mapping to the required array.
The inner workings of this mapping process are summarized in the documentation below:
const data=[{time:100,info:[{name:"thing1",count:3},{name:"thing2",count:2},{}]},{time:1e3,info:[{name:"thing1",count:7},{name:"thing2",count:0},{}]}];
const result =
/* Obtain array of values from outerMap reduce result */
Object.values(
/* Iterate array of data items by reduce to obtain mapping of
info.name to { time, count} value type */
data.reduce((outerMap, item) =>
/* Iterate inner info array of current item to compound
mapping of info.name to { time, count} value types */
item.info.reduce((innerMap, infoItem) => {
if(!infoItem.name) {
return innerMap
}
/* Fetch or insert new { name, info } value for result
array */
const nameInfo = innerMap[ infoItem.name ] || {
name : infoItem.name, info : []
};
/* Add { time, count } value to info array of current
{ name, info } item */
nameInfo.info.push({ count : infoItem.count, time : item.time })
/* Compound updated nameInfo into outer mapping */
return { ...innerMap, [ infoItem.name] : nameInfo }
}, outerMap),
{})
)
console.log(result)
Hope that helps!
The approach I would take would be to use an intermediate mapping object and then create the new array from that.
const data = [{time: 100, info: [{name: "thing1", count: 3}, {name: "thing2", count: 2}, {}]}, {time: 1e3, info: [{name: "thing1", count: 7}, {name: "thing2", count: 0}, {}]} ];
const infoByName = {};
// first loop through and add entries based on the name
// in the info list of each data entry. If any info entry
// is empty ignore it
data.forEach(entry => {
if (entry.info) {
entry.info.forEach(info => {
if (info.name !== undefined) {
if (!infoByName[info.name]) {
infoByName[info.name] = [];
}
infoByName[info.name].push({
time: entry.time,
count: info.count
});
}
});
}
});
// Now build the resulting list, where name is entry
// identifier
const keys = Object.keys(infoByName);
const newData = keys.map(key => {
return {
name: key,
info: infoByName[key]
};
})
// newData is the resulting list
console.log(newData);
Well, the other guy posted a much more elegant solution, but I ground this one out, so I figured may as well post it. :)
var data = [
{
time: 100,
info: [{
name: "thing1",
count: 3
}, {
name: "thing2",
count: 2
}, {
}]
},
{
time: 1000,
info: [{
name: "thing1",
count: 7
}, {
name: "thing2",
count: 0
}, {
}]
}
];
var newArr = [];
const objInArray = (o, a) => {
for (var i=0; i < a.length; i += 1) {
if (a[i].name === o)
return true;
}
return false;
}
const getIndex = (o, a) => {
for (var i=0; i < a.length; i += 1) {
if (a[i].name === o) {
return i;
}
}
return false;
}
const getInfoObj = (t, c) => {
let tmpObj = {};
tmpObj.count = c;
tmpObj.time = t;
return tmpObj;
}
for (var i=0; i < data.length; i += 1) {
let t = data[i].time;
for (var p in data[i].info) {
if ("name" in data[i].info[p]) {
if (objInArray(data[i].info[p].name, newArr)) {
let idx = getIndex(data[i].info[p].name, newArr);
let newInfoObj = getInfoObj(t, data[i].info[p].count);
newArr[idx].info.push(newInfoObj);
} else {
let newObj = {};
newObj.name = data[i].info[p].name;
let newInfo = [];
let newInfoObj = getInfoObj(t, data[i].info[p].count);
newInfo.push(newInfoObj);
newObj.info = newInfo;
newArr.push(newObj);
}}
}
}
console.log(newArr);
try to use Object.keys() to get the key

How to dedupe an array of objects by a key value pair?

// This is a large array of objects, e.g.:
let totalArray = [
{"id":"rec01dTDP9T4ZtHL4","fields":
{"user_id":170180717,"user_name":"abcdefg","event_id":516575,
}]
let uniqueArray = [];
let dupeArray = [];
let itemIndex = 0
totalArray.forEach(x => {
if(!uniqueArray.some(y => JSON.stringify(y) === JSON.stringify(x))){
uniqueArray.push(x)
} else(dupeArray.push(x))
})
node.warn(totalArray);
node.warn(uniqueArray);
node.warn(dupeArray);
return msg;
I need my code to identify duplicates in the array by a key value of user_id within the objects in the array. Right now, my code works to identify identical objects in the array, but I need it to identify dupes based on a key value inside the objects instead. How do I do this? I am struggling to figure out how to path the for each loop to identify the dupe based on the key value instead of the entire object.
Right now, my code works to identify identical objects in the array, but I need it to identify dupes based on a key value inside the objects instead. How do I do this?
Don’t compare the JSON representation of the whole objects then, but only their user_id property specifically.
totalArray.forEach(x => {
if(!uniqueArray.some(y => y.fields.user_id === x.fields.user_id)){
uniqueArray.push(x)
} else(dupeArray.push(x))
})
You could take a Set and push to either uniques or duplicates.
var array = [
{ id: 1, data: 0 },
{ id: 2, data: 1 },
{ id: 2, data: 2 },
{ id: 3, data: 3 },
{ id: 3, data: 4 },
{ id: 3, data: 5 },
],
uniques = [],
duplicates = [];
array.forEach(
(s => o => s.has(o.id) ? duplicates.push(o) : (s.add(o.id), uniques.push(o)))
(new Set)
);
console.log(uniques);
console.log(duplicates);
.as-console-wrapper { max-height: 100% !important; top: 0; }
One way is to keep a list of ids you found so far and act accordingly:
totalArray = [
{ id: 1, val: 10 },
{ id: 2, val: 20 },
{ id: 3, val: 30 },
{ id: 2, val: 15 },
{ id: 1, val: 50 }
]
const uniqueArray = []
const dupeArray = []
const ids = {}
totalArray.forEach( x => {
if (ids[x.id]) {
dupeArray.push(x)
} else {
uniqueArray.push(x)
ids[x.id] = true
}
})
for (const obj of uniqueArray) console.log("unique:",JSON.stringify(obj))
for (const obj of dupeArray) console.log("dupes: ",JSON.stringify(obj))

How to override specific value when object value is same as other object

https://jsfiddle.net/JungEun1997/nb3o1987/50/
I have reached the desired result but you want to see it in a simpler way.
I tried using map and filter but failed.
I want to change this obj_wrap to obj_a in a simpler way!
(start_num and end_num differ by 1)
var obj_wrap = {
'time':[{
'start_num': 10,
'end_num':11
},{
'start_num': 3,
'end_num':4
},{
'start_num': 1,
'end_num':2
},{
'start_num': 2,
'end_num':3
},{
'start_num': 6,
'end_num':7
}]
}
var obj_a = {
'time':[{
'start_num': 1,
'end_num':4
},{
'start_num': 6,
'end_num':7
},{
'start_num': 10,
'end_num':11
}]
}
I used this method.
var obj_b = {'time':[]}
$.each(obj_wrap.time,function(time_key,time_val){
$.each(obj_wrap.time,function(chk_key,chk_val){
if(time_val.start_num === chk_val.end_num){
obj_wrap.time[time_key]['start_num'] = chk_val.start_num
obj_wrap.time[chk_key] = ""
}
if(time_val.end_num === chk_val.start_num){
obj_wrap.time[time_key]['end_num'] = chk_val.end_num
obj_wrap.time[chk_key] = ""
}
});
})
$.each(obj_wrap.time,function(key,value){
if(value!==""){
obj_b.time.push(value)
}
})
obj_b.time.sort(function (a, b) {
return a.start_num < b.start_num ? -1 : a.start_num > b.start_num ? 1 : 0;
});
You can use Bucket Sort algorithm in this case:
var obj_wrap = {
'time':[{
'start_num': 10,
'end_num':11
},{
'start_num': 3,
'end_num':4
},{
'start_num': 1,
'end_num':2
},{
'start_num': 2,
'end_num':3
},{
'start_num': 6,
'end_num':7
}]
};
var time = obj_wrap.time;
var bucket = [];
time.forEach(({start_num, end_num}) => {
for (var i = start_num; i < end_num; i++) {
bucket[i] = true;
}
});
var newTime = [];
bucket.forEach((_, index) => {
if (bucket[index - 1]) {
newTime[newTime.length - 1].end_num = index + 1;
} else {
newTime.push({start_num: index, end_num: index + 1});
}
});
var obj_a = {time: newTime};
console.log(obj_a);
The complexity is O(n).
I've implemented just a simple memoized cache of your data with the Key Value pair representing start_num & end_num values (See code comments for visual).
Once the memo has been created, you can iterate across the memo in linear time, and populate a results array accordingly. For that part, i opted for reduce, since it persists a transient state that's accessible for each iteration.
On each iteration, i basically just check to see if I should continue iterating without populating the times array. Once i've detected a break in the number chain, there's some edge case checks conducted before populating the times array with the expected results.
Time & Space Complexity is O(n).
const objWrap = {
time:[{
start_num: 10,
end_num:11
}, {
start_num: 3,
end_num:4
}, {
start_num: 1,
end_num:2
}, {
start_num: 2,
end_num:3
}, {
start_num: 6,
end_num:7
}],
};
const memo = objWrap.time.reduce((acc, next) => {
if (!Reflect.has(acc, next.start_num)) {
acc[next.start_num] = next.end_num;
}
return acc;
}, {});
/*
memo is now:
{
1: 2,
2: 3,
3: 4,
6: 7,
10: 11
}
NOTE: If you store key's as numbers in a JS object, they'll be automatically sorted.
*/
const entries = Object.entries(memo);
const result = entries
.slice(1) // iterate across all entries except the first since we'll use the first entry to initialize our accumulator.
.reduce((acc, [start,end], i, arr) => {
if (Reflect.has(memo, acc.next)) { // if we found a sequence, then just continue iterating.
acc.next = end;
} else {
acc.times.push({ // if the sequence is broken, then we have a result.
start_num: Number(acc.start), // cast back to number, as it's currently a string
end_num: acc.next,
});
if (i === arr.length - 1) { // if we've reached the end of the array, then prepare the last result as well.
acc.times.push({
start_num: Number(start),
start_end: end,
});
delete acc.next;
delete acc.start;
} else { // if we haven't reached the end of the array, then prepare the next iteration's comparison.
acc.start = start;
acc.next = end;
}
}
return acc;
}, {
next: entries[0][1], // initialize accumulator with first entryies end value.
start: entries[0][0], // initialize accumulator with first entryies start value.
times: [],
});
console.log(JSON.stringify(result, null, 2))

how to count duplicate values object to be a value of object

how to count the value of object in new object values
lets say that i have json like this :
let data = [{
no: 3,
name: 'drink'
},
{
no: 90,
name: 'eat'
},
{
no: 20,
name: 'swim'
}
];
if i have the user pick no in arrays : [3,3,3,3,3,3,3,3,3,3,3,90,20,20,20,20]
so the output should be an array
[
{
num: 3,
total: 11
},
{
num: 90,
total: 1
},
{
num:20,
total: 4
}
];
I would like to know how to do this with a for/of loop
Here is the code I've attempted:
let obj = [];
for (i of arr){
for (j of data){
let innerObj={};
innerObj.num = i
obj.push(innerObj)
}
}
const data = [{"no":3,"name":"drink"},{"no":90,"name":"eat"},{"no":20,"name":"swim"}];
const arr = [3,3,3,3,3,3,3,3,3,3,3,20,20,20,20,80,80];
const lookup = {};
// Loop over the duplicate array and create an
// object that contains the totals
for (let el of arr) {
// If the key doesn't exist set it to zero,
// otherwise add 1 to it
lookup[el] = (lookup[el] || 0) + 1;
}
const out = [];
// Then loop over the data updating the objects
// with the totals found in the lookup object
for (let obj of data) {
lookup[obj.no] && out.push({
no: obj.no,
total: lookup[obj.no]
});
}
document.querySelector('#lookup').textContent = JSON.stringify(lookup, null, 2);
document.querySelector('#out').textContent = JSON.stringify(out, null, 2);
<h3>Lookup output</h3>
<pre id="lookup"></pre>
<h3>Main output</h3>
<pre id="out"></pre>
Perhaps something like this? You can map the existing data array and attach filtered array counts to each array object.
let data = [
{
no: 3,
name: 'drink'
},
{
no:90,
name: 'eat'
},
{
no:20,
name: 'swim'
}
]
const test = [3,3,3,3,3,3,3,3,3,3,3,90,20,20,20,20]
const result = data.map((item) => {
return {
num: item.no,
total: test.filter(i => i === item.no).length // filters number array and then checks length
}
})
You can check next approach using a single for/of loop. But first I have to create a Set with valid ids, so I can discard noise data from the test array:
const data = [
{no: 3, name: 'drink'},
{no: 90, name: 'eat'},
{no: 20, name: 'swim'}
];
const userArr = [3,3,3,3,3,3,3,3,7,7,9,9,3,3,3,90,20,20,20,20];
let ids = new Set(data.map(x => x.no));
let newArr = [];
for (i of userArr)
{
let found = newArr.findIndex(x => x.num === i)
if (found >= 0)
newArr[found].total += 1;
else
ids.has(i) && newArr.push({num: i, total: 1});
}
console.log(newArr);

Categories