I have the below object obj(coming as a JSON response):
var obj = {
0: {
note: 'test1',
id: 24759045,
createTimeStamp: '2022-08-01T17:05:36.750Z',
},
1: {
note: 'test2',
id: 24759045,
createTimeStamp: '2022-08-01T17:05:51.755Z',
},
note: 'test1',
id: 24759045,
createTimeStamp: '2022-08-01T17:05:36.750Z',
};
I only want the objects with numbers("0" , "1" .. so on) to be pushed in an array.
Below is what I am trying to do:
let items = [];
for (var prop in obj) {
items.push(obj[prop]);
}
console.log(items);
// expected output:
[
{
note: 'test1',
id: 24759045,
createTimeStamp: '2022-08-01T17:05:36.750Z',
},
{
note: 'test2',
id: 24759045,
createTimeStamp: '2022-08-01T17:05:51.755Z',
},
]
Any pointers would be highly appreciated.
A few things to consider here.
Are the numeric keys ordered?
Does the order matter?
Are the numeric keys an index of the item in the array?
Are there any gaps in the numeric keys?
First solution, assuming that the numeric keys are the index in the array.
const items = Object.keys(obj).reduce((acc, key) => {
const index = parseInt(key);
if (Number.isNaN(index)) {
return acc;
}
acc[index] = obj[key];
return acc;
}, []);
Second solution, assuming that order matters, but that the numeric keys are not guaranteed to be contiguous.
const items = Object.keys(obj)
.filter((key) => Number.isNaN(parseInt(key)) === false)
.sort()
.map((key) => obj[key]);
Keep in mind that Object.keys does not guarantee that the keys are ordered alpha-numerically. So if order matters, then you have to sort them.
Third solution, if order doesn't matter.
const items = Object.keys(obj)
.filter((key) => Number.isNaN(parseInt(key)) === false)
.map((key) => obj[key]);
var result = [];
var obj = {
"0": {
"note": "test1",
"id": 24759045,
"createTimeStamp": "2022-08-01T17:05:36.750Z"
},
"1": {
"note": "test2",
"id": 24759045,
"createTimeStamp": "2022-08-01T17:05:51.755Z"
},
"note": "test1",
"id": 24759045,
"createTimeStamp": "2022-08-01T17:05:36.750Z"
}
for (var i in obj)
result.push(obj[i]);
$('#result').html(JSON.stringify(result));
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="result"></div>
You can achieve this by doing the following steps.
Copied your object below -->
var obj = {
"0": {
"note": "test1",
"id": 24759045,
"createTimeStamp": "2022-08-01T17:05:36.750Z"
},
"1": {
"note": "test2",
"id": 24759045,
"createTimeStamp": "2022-08-01T17:05:51.755Z"
},
"note": "test1",
"id": 24759045,
"createTimeStamp": "2022-08-01T17:05:36.750Z"
}
Created new js array -->
var result = [];
Code -->
for (var i in obj)
result.push(obj[i]);
Find the solution from link below as well --> :) :)
https://jsfiddle.net/kavinduxo/95qnpaed/
I think you'll need to get the keys of the object, filter out the non-numeric ones, then map each key to the obj[key]:
var obj={"0":{"note":"test1","id":24759045,
"createTimeStamp":"2022-08-01T17:05:36.750Z"},"1":{"note":"test2","id":24759045,
"createTimeStamp":"2022-08-01T17:05:51.755Z"},
"note":"test1","id":24759045,"createTimeStamp":"2022-08-01T17:05:36.750Z"};
console.log(
Object.keys(obj)
.filter((key) =>!Number.isNaN(parseInt(key)))
.map((key) => obj[key])
)
Related
Given the following object, how can I loop through this object inorder to obtain both keys and values but only for the following keys:
"myName": "Demo"
"active": "Y"
"myCode": "123456789"
"myType": 1
let a = {
"values": {
"myName": "Demo",
"active": "Y",
"myCode": "123456789",
"myType": 1,
"myGroups": [
{
"myGroupName": "Group 1",
"myTypes": [
{
"myTypeName": "323232",
"myTypeId": "1"
}
]
},
{
"myGroupName": "Group 2",
"myTypes": [
{
"myTypeName": "523232",
"myTypeId": "2"
}
]
}
]
}
}
I have tried:
for (const [key, value] of Object.entries(a.values)) {
console.log(`${key}: ${value}`);
For}
but this will return all keys with their values.
You can use a dictionary (array) to contain the keys you want to extract the properties for, and then reduce over the values with Object.entries to produce a new object matching only those entries included in the dictionary.
let a = {
"values": {
"myName": "Demo",
"active": "Y",
"myCode": "123456789",
"myType": 1,
"myGroups": [{
"myGroupName": "Group 1",
"myTypes": [{
"myTypeName": "323232",
"myTypeId": "1"
}]
},
{
"myGroupName": "Group 2",
"myTypes": [{
"myTypeName": "523232",
"myTypeId": "2"
}]
}
]
}
}
const arr = [ 'myName', 'active', 'myCode', 'myType' ];
const out = Object.entries(a.values).reduce((acc, [key, value]) => {
if (arr.includes(key)) acc[key] = value;
return acc;
}, {});
console.log(out);
The best answer would be to set up an array of the desired keys and then iterate over that array instead of an array of the original object's entries. This is how you would achieve that:
let a = {
values: {
myName: "Demo",
active: "Y",
myCode: "123456789",
myType: 1,
myGroups: [{
myGroupName: "Group 1",
myTypes: [{
myTypeName: "323232",
myTypeId: "1"
}]
}, {
myGroupName: "Group 2",
myTypes: [{
myTypeName: "523232",
myTypeId: "2"
}]
}]
}
};
const keys = ['myName', 'active', 'myCode', 'myType'];
const cherryPick = (obj, keys) => keys.reduce((a,c) => (a[c] = obj[c], a), {});
console.log(cherryPick(a.values, keys));
The above example will work for many provided keys. If a key does not exist in the supplied object, its value will be undefined. If you want to only keep properties which have values, simply add an optional filter to the cherryPick() function, like this:
let test = {
a: 1,
b: 2
};
const keys = ['a', 'b', 'c'];
const cherryPick = (obj, keys, filter = 0) => keys.filter(key => filter ? obj[key] : 1).reduce((acc,key) => (acc[key] = obj[key], acc), {});
console.log('STORE undefined :: cherryPick(test, keys)', cherryPick(test, keys));
console.log('FILTER undefined :: cherryPick(test, keys, 1)', cherryPick(test, keys, true));
/* Ignore this */ .as-console-wrapper { min-height: 100%; }
If the fields key in a object is array, change the first value of arrays as a key value pair object in javascript.
var obj =
[
{ id:1, fields:["item", "2", "list"]},
{ id:2, fields:["sample", "1", "check"]}
]
function newObj(obj) {
let objFields = {};
modifiedObj.fields.forEach(field => objFields[field] = field);
modifiedObj.fields= objFields;
return modifiedObj;
}
var result = this.newObject(obj)
Expected Output
{
item: "item",
sample: "sample"
}
Try this:
var obj =
[
{ id:1, fields:["item", "2", "list"]},
{ id:2, fields:["sample", "1", "check"]}
]
function newObject(obj) {
let objFields = {};
obj.forEach(e => {
if(e.fields && e.fields.length>0)
objFields[e.fields[0]] = e.fields[0];
});
return objFields;
}
var result = this.newObject(obj);
console.log(result);
Here is a functional approach that makes use of Object.assign(), spread operator, and Array.map() to create the object you need.
const input = [
{ id: 1, fields: ["item", "2", "list"] },
{ id: 2, fields: ["sample", "1", "check"] }
];
const process = (input) => (Object.assign(...input.map(({ fields }) => (
fields.length ? { [fields[0]]: fields[0] } : {}
))));
console.log(process(input));
Your snippet was close, you just needed to clean up the variable names, and then using map makes it a bit neater too:
const obj = [
{id: 1, fields: ["item", "2", "list"]},
{id: 2, fields: ["sample", "1", "check"]}
]
function newObj(inputArray) {
let outputObject = {};
inputArray.map(item => item.fields[0])
.forEach(field => outputObject[field] = field);
return outputObject;
}
var result = newObj(obj)
console.log(result)
In JavaScript I have 2 object arrays that have the same objects but are in a different order. I'm trying to figure out how to sort one array based on the order of the other. There is a unique field they both share (sortField below) I'm just failing on figuring out how to sort with it. Here's an example of my arrays:
sorter array:
[
{
"displayName": "Party",
"sortField": "com.uniqueXbd",
"elementId": "PtyListPanel"
}, {
"displayName": "Group",
"sortField": "com.uniqueARd",
"elementId": "GrpListPaneARd"
}, {
"displayName": "Leader",
"sortField": "com.uniqueEcF",
"elementId": "LeaderListPaneEcF"
}
]
needsSorted array:
[
{
"displayName": "Group",
"sortField": "com.uniqueARd",
"elementId": "GrpListPaneARd"
}, {
"displayName": "Leader",
"sortField": "com.uniqueEcF",
"elementId": "LeaderListPanel"
}, {
"displayName": "Party",
"sortField": "com.uniqueXbd",
"elementId": "PtyListPaneEcF"
}
]
I'm guessing it's going to look something like this?
needsSorted.sort((a, b) => {
if(sorter.sortField...){
return 1
})
Thanks
const output = [];
sortedArray.forEach( sortedItem => {
const matchingItem = unsortedArray.find( unsortedItem => unsortedItem.sortField === sortedItem.sortField );
if(matchingItem){
output.push(matchingItem);
}
});
Since you know the second array is the order you want the items from the first array to be in, you should loop through it. Then find the matching item from the first list, and push it into your output in that order.
You can make a sorting lookup that maps the sort key to the index in the original array. Then in your sort, you can look it up for both objects in the comparison.
This replaces the repeated need to lookup the index in the original array for each comparison with a constant time object lookup so it should be more performant for larger arrays at the expense of the space for the lookup object.
let sortObj = [{"displayName": "Party","sortField": "com.uniqueXbd","elementId": "PtyListPanel"}, {"displayName": "Group","sortField": "com.uniqueARd","elementId": "GrpListPaneARd"}, {"displayName": "Leader","sortField": "com.uniqueEcF","elementId": "LeaderListPaneEcF"}]
let needsSorted = [{"displayName": "Group","sortField": "com.uniqueARd","elementId": "GrpListPaneARd"}, {"displayName": "Leader","sortField": "com.uniqueEcF","elementId": "LeaderListPanel"}, {"displayName": "Party","sortField": "com.uniqueXbd","elementId": "PtyListPaneEcF"}]
let sortLookup = sortObj.reduce((obj, item, idx) => {
obj[item.sortField] = idx
return obj
}, {})
needsSorted.sort((a,b) => sortLookup[a.sortField] - sortLookup[b.sortField])
console.log(needsSorted)
var obj = [
{
"one": 1,
"two": 9
}, {
"one": 3,
"two": 5
}, {
"one": 1,
"two": 2
}
];
var obj = [
{
"one": 1,
"two": 2,
}, {
"one": 1,
"two": 9
}, {
"one": 3,
"two": 5
}
];
obj.sort(function(a, b) {
return a["one"] - b["one"] || a["two"] - b["two"];
});
const sortedIndexes = sorter.map(i => i.sortField);
needsSorted.sort((a, b) => {
const aIndex = sortedIndexes.findIndex((i) => i === a.sortField);
const bIndex = sortedIndexes.findIndex((i) => i === b.sortField);
return aIndex - bIndex;
})
Given that you just want to compare the two arrays and make sure they are still the same, I would go about it differently:
const first = sorted.sort((a, b) => a.localCompare(b))
const second = needsSorting.sort((a, b) => a.localCompare(b))
if (JSON.stringify(first) != JSON.stringify(second)) {
console.log("the array was modified!");
}
const sortOrder = sorted.map(item => item.sortField);
needsSorted.sort((a, b) => {
return sortOrder.indexOf(a.sortField) > sortOrder.indexOf(b.sortField) ? 1 : -1;
});
const fields = sorted.map(x => x.sortField);
const value = x => fields.indexOf(x.sortField);
needSorted.sort((a, b) => value(a) - value(b));
console.log(needSorted);
const sorted = [
{
displayName: "Party",
sortField: "com.uniqueXbd",
elementId: "PtyListPanel"
},
{
displayName: "Group",
sortField: "com.uniqueARd",
elementId: "GrpListPaneARd"
},
{
displayName: "Leader",
sortField: "com.uniqueEcF",
elementId: "LeaderListPaneEcF"
}
];
const needSorted = [
{
displayName: "Group",
sortField: "com.uniqueARd",
elementId: "GrpListPaneARd"
},
{
displayName: "Leader",
sortField: "com.uniqueEcF",
elementId: "LeaderListPanel"
},
{
displayName: "Party",
sortField: "com.uniqueXbd",
elementId: "PtyListPaneEcF"
}
];
const fields = sorted.map(x => x.sortField);
const value = x => fields.indexOf(x.sortField);
needSorted.sort((a, b) => value(a) - value(b));
console.log(needSorted);
I have an array which has some objects and one of the propery of the object can have dupes viz. Account. Now i want to convert this array to map with key having Account's property value and the corresponding dupes should be stored as an array to that key in the map.
let arr = [];
arr.push({'Key':'1','Record':{'Account':'a','data':'A1'}});
arr.push({'Key':'2','Record':{'Account':'b','data':'123'}});
arr.push({'Key':'3','Record':{'Account':'a','data':'A2'}});
arr.push({'Key':'4','Record':{'Account':'a','data':'A3'}});
arr.push({'Key':'5','Record':{'Account':'c','data':'123'}});
const accIdMap= arr.reduce((map,obj) => (map[obj.Record.Account] = obj,map), {});
console.log(arr);
console.log(accIdMap);
So as of now the accIdMap just gets a one to one key-value mapping which is the last one pushed in the array i.e 4 but i want that the output map should have value as an array where ever the keys were duplicated. I tried reduction but that eliminates the duplicate values but i want the duplicate values as an corresponding array.
For example
As is output
{
"a": {
"Key": "4",
"Record": {
"Account": "a",
"data": "A3"
}
},
"b": {
"Key": "2",
"Record": {
"Account": "b",
"data": "123"
}
},
"c": {
"Key": "5",
"Record": {
"Account": "c",
"data": "123"
}
}
}
Desired OutPut (the keys which were duplicated should have the values added as an array)
{
"a": [{"Key": "4","Record": {"Account": "a","data": "A3"}},{
"Key": "3",
"Record": {
"Account": "a",
"data": "A2"
}
},{
"Key": "1",
"Record": {
"Account": "a",
"data": "A1"
}
}],
"b": {
"Key": "2",
"Record": {
"Account": "b",
"data": "123"
}
},
"c": {
"Key": "5",
"Record": {
"Account": "c",
"data": "123"
}
}
}
You can use reduce like this:
Check if the accumulator already has key with current a.Record.Account. If yes, push the current item in context to it. Else, add a.Record.Account as a key and then push the item to it.
const input = [{'Key':'1','Record':{'Account':'a','data':'A1'}},
{'Key':'2','Record':{'Account':'b','data':'123'}},
{'Key':'3','Record':{'Account':'a','data':'A2'}},
{'Key':'4','Record':{'Account':'a','data':'A3'}},
{'Key':'5','Record':{'Account':'c','data':'123'}}]
const output = input.reduce((acc, a) =>
((acc[a.Record.Account] = acc[a.Record.Account] || []).push(a), acc), {})
console.log(output);
Doing a check in the reduce function if the value exists already, then based on that you can do the following. If the Account already exists then check if the map has a array on that Account's key. If not create an array with the existing element and the current one by creating an empty array and pushing to that. If it is an array then just push to it. If the Account key doesn't exist then just set the value as the obj.
Update: Reordered the initialization of const m and added comment on code.
let arr = [];
arr.push({'Key':'1','Record':{'Account':'a','data':'A1'}});
arr.push({'Key':'2','Record':{'Account':'b','data':'123'}});
arr.push({'Key':'3','Record':{'Account':'a','data':'A2'}});
arr.push({'Key':'4','Record':{'Account':'a','data':'A3'}});
arr.push({'Key':'5','Record':{'Account':'c','data':'123'}});
const accIdMap= arr.reduce((map,obj) => {
if(map[obj.Record.Account]) { // the property exists and can be an array or the obj
if(!map[obj.Record.Account].length) { // means just the object. Creating an array then pushing the existing obj to it
const m = (map[obj.Record.Account]);
map[obj.Record.Account] = [];
map[obj.Record.Account].push(m);
}
map[obj.Record.Account].push(obj); // if it was an array this will push it to the existing array. If it wasn't the previous if have created and inserted old value and this line pushes to the new array
} else {
map[obj.Record.Account] = obj; // just putting the obj value as it wasn't a duplicate
}
return map;
}, {});
console.log(arr);
console.log(accIdMap);
This works like what you expected. take this result and match with your desired output.
let arr = [];
arr.push({ 'Key': '1', 'Record': { 'Account': 'a', 'data': 'A1' } });
arr.push({ 'Key': '2', 'Record': { 'Account': 'b', 'data': '123' } });
arr.push({ 'Key': '3', 'Record': { 'Account': 'a', 'data': 'A2' } });
arr.push({ 'Key': '4', 'Record': { 'Account': 'a', 'data': 'A3' } });
arr.push({ 'Key': '5', 'Record': { 'Account': 'c', 'data': '123' } });
var obj = {}
arr.map((e) => {
var filteredArr = arr.filter((f) => f.Record.Account == e.Record.Account)
if (filteredArr.length > 1)
obj[e.Record.Account] = filteredArr
else if (filteredArr.length != 0)
obj[e.Record.Account] = filteredArr[0]
})
console.log(JSON.stringify(obj))
I have a series of JSON entries:
[{"num": "1","name_A": "Alex" ,"name_B": "Bob"}, {"num": "2","name_A": "Anne" ,"name_B": "Barbra"}]
I am trying to convert this array of Objects as painlessly as possible into two objects - one with title name_A, and the second with the title name_B. Objects have to contain the title and an array of matching num-name pairs:
[{title: "name_A", names:[{"1", "Alex}, {"2", "Anne"}]}, {title:"name_B", names: [{"1", "Bob"}, {"2", "Barbra"}]}]
At first I tried simply to create two objects by reducing the array of object twice, once for name_A and second time for name_B and later glue everything together:
// get 'names' array
var name_A = objArray.reduce(function(memo, curr) {
memo.push({curr.num, curr.name_A})
return memo;
}, []);
But even this is failing. Why there is no push method for memo if I initialize reduce with an empty array?
And second question, am I on a right track or is there a better way to achieve this?
Comments inline, made a few minor corrections to the expectations.
var input = [{ "num": "1", "name_A": "Alex", "name_B": "Bob" }, { "num": "2", "name_A": "Anne", "name_B": "Barbra" }]
var output = input.reduce(function (a, b) {
// construct new objects and set their properties
var i = {};
i[b.num] = b.name_A;
var j = {};
j[b.num] = b.name_B;
// add them to our collection elements
a[0].names.push(i);
a[1].names.push(j);
return a;
// initializing our collection
}, [{ title: "name_A", names: [] }, { title: "name_B", names: [] }]);
// pretty print our output
console.log(JSON.stringify(output, null, " "))
var input = [{ "num": "1", "name_A": "Alex", "name_B": "Bob" }, { "num": "2", "name_A": "Anne", "name_B": "Barbra" }]
var output = input.reduce(function (a, b) {
// construct new objects and set their properties
var i = {};
i[b.num] = b.name_A;
var j = {};
j[b.num] = b.name_B;
// add them to our collection elements
a[0].names.push(i);
a[1].names.push(j);
return a;
// initializing our collection
}, [{ title: "name_A", names: [] }, { title: "name_B", names: [] }]);
so.log(output)
<pre id="output"></pre>
<script>
var so = {
log: function(o) {
document.getElementById("output").innerHTML = JSON.stringify(o, null, " ")
}
}
</script>
The problem with your code is that { curr.num, curr.name_A } is not a valid object, it's missing the property names. I've added properties num and name in my code below.
var name_A = [];
var name_B = [];
objArray.forEach(function(curr) {
name_A.push({num: curr.num, name: curr.name_a});
name_B.push({num: curr.num, name: curr.name_B});
});
var result = [
{ title: "name_A" }, names: name_A },
( title: "name_B" }, names: name_B }
];
Also, if you want to make an array out of the results of looping over an array, you should use .map rather than .reduce.
Assuming only property num is fixed. All other properties are treated as data, like name_A or name_B.
var a = [{ "num": "1", "name_A": "Alex", "name_B": "Bob" }, { "num": "2", "name_A": "Anne", "name_B": "Barbra" }],
result = [];
a.forEach(function (el) {
var num = el.num;
Object.keys(el).forEach(function (k) {
function tryFindIndexAndSetNames(aa, i) {
if (aa.title === k) {
result[i].names[num] = el[k];
return true;
}
}
if (k !== 'num' && !result.some(tryFindIndexAndSetNames)) {
var o = {};
o[num] = el[k];
result.push({ title: k, names: o });
}
});
});
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');