Create new array based of two different arrays (match values) - javascript

I have two arrays in JavaScript and I want to re-arrange one based on the order of the first.
First array:
var arrayOne = [
"5",
"1",
"2",
"4"
]
Second array that I want to re-arrange based on page_id that matches to arrayOne:
var arrayTwo = [
{
"page_id" : "5",
"page_title" : "About"
},
{
"page_id" : "2",
"page_title" : "Home"
},
{
"page_id" : "4",
"page_title" : "Contact Us"
},
{
"page_id" : "1",
"page_title" : "Gallery"
},
];
After re-arranged
I want to re-arrange arrayTwo based on page_id, so once re-arranged the second array will look this like:
var arrayTwo = [
{
"page_id" : "5",
"page_title" : "About"
},
{
"page_id" : "1",
"page_title" : "Gallery"
},
{
"page_id" : "2",
"page_title" : "Home"
},
{
"page_id" : "4",
"page_title" : "Contact Us"
},
];
I'm pretty stuck at this point, I've found many sorting 'solutions' on here and Google but they just don't seem to work. I've tried using a for-loop to do this but I didn't really get anywhere. I wouldn't normally ask for help but I've been stuck for a good 3 hours searching.
The match between the first is matched with page_id in the second so there's a match that I can use but as mentioned I'm pretty stuck.
Any help is greatly appreciated, thanks!

First convert the second array into an object - the key will be the page_id, for example:
var map = arrayTwo.reduce((a, b) => {
a[b.page_id] = b;
return a;
}, {});
Now we can easily map the first array, like:
arrayOne.map(x => map[x]);
Working example: http://jsbin.com/tiyudutasi/edit?js,console

You can use Array.prototype.map() to iterate arrayOne, Array.prototype.filter() to match object at arrayTwo having page_id equal to current arrayOne value
var arrayOne = [
"5",
"1",
"2",
"4"
];
var arrayTwo = [{
"page_id": "5",
"page_title": "About"
}, {
"page_id": "2",
"page_title": "Home"
}, {
"page_id": "4",
"page_title": "Contact Us"
}, {
"page_id": "1",
"page_title": "Gallery"
}];
arrayTwo = arrayOne.map(function(id) {
return arrayTwo.filter(function(obj) {
return obj.page_id === id
})[0]
});
console.log(arrayTwo);

You first create an "index" that given an object number can return the number:
var index = {};
arrayTwo.forEach(function(obj){index[obj.page_id] = obj;});
then you can use the index to reorder the objects:
var reordered = arrayOne.map(function(id){return arrayTwo[id];});

You can also use 2 forEach (one per array)
var arrayOne = [
"5",
"1",
"2",
"4"
]
var arrayTwo = [
{
"page_id" : "5",
"page_title" : "About"
},
{
"page_id" : "2",
"page_title" : "Home"
},
{
"page_id" : "4",
"page_title" : "Contact Us"
},
{
"page_id" : "1",
"page_title" : "Gallery"
},
];
var result = [];
arrayOne.forEach(item => arrayTwo.forEach(element => { if (item === element.page_id) result.push(element)}));
console.log(result);

I think using find will be more readable.
arrayOne.map(id => arrayTwo.find(row => row.page_id === id));
If you need to support more browsers, you can use sort instead.
arrayTwo.sort((a, b) => arrayOne.indexOf(a.page_id) - arrayOne.indexOf(b.page_id));

Related

Filter nested object structure

I have an object with keys representing a schema. A schema contains a definition of columns and I want to end up with a list of columns that match a specific condition. I can use a for each but think it should also be possible to achieve with a filter or reduce; however getting stuck accessing the nested portion and accumulate the results.
I tried a number of variants, with reduce, spread operators but not achieving the desired result.
Hope anyone can pull me out of the quicksand, I tend to sink deeper with every move I make.
<script type="text/javascript">
let data = {
"Schema A" : [{"Id" : "1", "Type" : "measure"}, {"Id" : "2", "Type" : "dimension"}, {"Id" : "3", "Type" : "measure"}],
"Schema B" : [{"Id" : "4", "Type" : "measure"}, {"Id" : "5", "Type" : "dimension"}, {"Id" : "6", "Type" : "measure"}],
};
var d = Object.entries(data); // convert to array
console.log(d);
let result = d.map(val => {
return val.filter(x => x[1].Type === 'measure');
});
console.log(result);
</script>
You need to take the values from the key/value entries for filtering.
const
data = { "Schema A": [{ Id: "1", Type: "measure" }, { Id: "2", Type: "dimension" }, { Id: "3", Type: "measure" }], "Schema B" : [{ Id: "4", Type: "measure" }, { Id: "5", Type: "dimension" }, { Id: "6", Type: "measure" }] },
result = Object
.entries(data)
.map(([k, v]) => [k, v.filter(({ Type }) => Type === 'measure')]);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

lodash filter by single value and value in array

I have a quick and easy function that I need to use lodash for.
let obj =
{
"AttributeID": "1",
"KeyID": "0",
"Value": "Undefined",
"MetaInsertUtc": "2017-09-13T01:52:22.280"
},
{
"AttributeID": "1",
"KeyID": "1",
"Value": "Tier 1",
"MetaInsertUtc": "2017-09-13T01:52:22.280"
}, {
"AttributeID": "1",
"KeyID": "2",
"Value": "Tier 2",
"MetaInsertUtc": "2017-09-13T01:52:22.280"
}, {
"AttributeID": "1",
"KeyID": "3",
"Value": "Tier 3",
"MetaInsertUtc": "2017-09-13T01:52:22.280"
}, {
"AttributeID": "1",
"KeyID": "4",
"Value": "Tier 4",
"MetaInsertUtc": "2017-09-13T01:52:22.280"
}
let parent = 1;
let children = ['1', '2', '3', '4'];
let test = _.filter(obj, function(item) {
return parseInt(item.AttributeID) === parent && parseInt(item.KeyID) IN[Children];
})
I am trying to filter my objects by a specific parent ID and within those results, find all those that have KeyID that are in our children array.
Update:
Here is my end result based on the selected answer. If there is a more shorthand way to do this by chaining some of these lodash methods together, let me know.
let valueObj = {
"id" : "1",
"name": "Joe"
},
{
"id" : "2",
"name": "Bob"
}
let selectedValues = _.map(valueObj, 'id');
let result = _.filter(obj, function(item) {
return item.AttributeID === attributeID && _.includes(selectedValues, item.KeyID);
});
Use lodash#includes method. If children array contains string values, you shouldn't convert item.KeyID to a number, just compare two strings:
let test = _.filter(obj, function(item) {
let attrId = parseInt(item.AttributeID);
return attrId === parent && _.includes(children, item.KeyID);
});
Assuming your obj is actually an array.
object.filter(item => {
return parseInt(item['AttributeID']) === parent && children.indexOf(parseInt(item['AttributeID'])) > -1;
});
You can do this simple filtering in regular JS.

Iterating json array objects using node js

I have got a task to iterate through the complex json file that contains json array. I could not access the array object from the json file.
I need to access the particularly the class-name object from the json
file.
classdetail.json
[ [ { "student" : [
{
"name" : "AAaa",
"class-name" : "A",
"grade-label" : "AA" },
{
"name" : "AAbb",
"class-name" : "A",
"grade-label" : "AB" },
{
"name" : "AAcc",
"class-name" : "A",
"grade-label" : "AB" },
{
"name" : "AAdd",
"class-name" : "B",
"grade-label" : "AA" } ],
"Average" : 2.5 },
{
"student" : [
{
"name" : "BBaa",
"class-name" : "B",
"grade-label" : "AB" },
{
"name" : "BBbb",
"class-name" : "B",
"grade-label" : "AA" },
{
"name" : "BBcc",
"class-name" : "B",
"grade-label" : "AA" },
{
"name" : "BBdd",
"class-name" : "B",
"grade-label" : "AA" } ],
"Average" : 2.5 } ] ]
iterate.js
var fs = require('fs');
var express = require('express');
var http = require('http');
var publicApis;
var item;
var subItem;
classmem = JSON.parse(fs.readFileSync("classdetail.json", "utf8"));
for (item in classmem) {
for (subItem in classmem[item]) {
console.log(classmem[item][subItem]);
}
}
for (item in classmem) {
for (subItem in classmem[item]) {
var student = classmem[item][subItem].student;
for (row in student) {
console.log(student[row]['class-name']);
}
}
}
But read about Array.forEach.
for...in iterates over object properties in arbitrary order. It might not be what you want to use for an array, which stores items in a well-defined order. (though it should work in this case)
Try Array.forEach():
// iterate over `classmem`
classmem.forEach(function(element, index, array) {
// iterate over classmem[index], which is an array too
element.forEach(function(el, idx, arr) {
// classmem[index][idx] contains objects with a `.student` property
el.student.forEach(function(e, i, a) {
console.log(e["name"], e["class-name"], e["grade-label"]);
});
});
});
first check the value is array then access to the "class-name" value
for (item in classmem) {
for (subItem in classmem[item]) {
**if (typeof classmem[item][subItem] === 'object') {
classmem[item][subItem].forEach(function (val, ind) {
console.log(val['class-name']);
});
}**
}
}

JSON Object array inside array find and replace in javascript

I have one JSON Object like this :
var myObject = [
{
"Name" : "app1",
"id" : "1",
"groups" : [
{ "id" : "test1",
"name" : "test group 1",
"desc" : "this is a test group"
},
{ "id" : "test2",
"name" : "test group 2",
"desc" : "this is another test group"
}
]
},
{
"Name" : "app2",
"id" : "2",
"groups" : [
{ "id" : "test3",
"name" : "test group 4",
"desc" : "this is a test group"
},
{ "id" : "test4",
"name" : "test group 4",
"desc" : "this is another test group"
}
]
},
{
"Name" : "app3",
"id" : "3",
"groups" : [
{ "id" : "test5",
"name" : "test group 5",
"desc" : "this is a test group"
},
{ "id" : "test6",
"name" : "test group 6",
"desc" : "this is another test group"
}
]
}
];
I have new value available of "name" for specific "id".
How can I replace "name" of specific "id" inside any object ?
And how to count total number of groups among all objects ?
for example : replace name to "test grp45" for id = "test1"
Here is fiddle
http://jsfiddle.net/qLTB7/21/
The following function will search through an object and all of its child objects/arrays, and replace the key with the new value. It will apply globally, so it won't stop after the first replacement. Uncomment the commented line to make it that way.
function findAndReplace(object, value, replacevalue) {
for (var x in object) {
if (object.hasOwnProperty(x)) {
if (typeof object[x] == 'object') {
findAndReplace(object[x], value, replacevalue);
}
if (object[x] == value) {
object["name"] = replacevalue;
// break; // uncomment to stop after first replacement
}
}
}
}
Working jsfiddle: http://jsfiddle.net/qLTB7/28/
Try this
function findAndReplace(object,keyvalue, name) {
object.map(function (a) {
if (a.groups[0].id == keyvalue) {
a.groups[0].name = name
}
})
}
findAndReplace(myObject,"test1" ,"test grp45");
Here's a different approach using Array.prototype.some. It assumes that the Name property in the outer objects should be actually be name (note capitalisation).
function updateNameById(obj, id, value) {
Object.keys(obj).some(function(key) {
if (obj[key].id == id) {
obj[key].name = value;
return true; // Stops looping
}
// Recurse over lower objects
else if (obj[key].groups) {
return updateNameById(obj[key].groups, id, value);
}
})
}
The advantage of some is that it stops as soon as the callback returns true.
I think this should work for you:-
var id = 'test1';
var newname = 'test grp45';
var numberOfGruops = 0;
myObject.forEach(function(app){
numberOfGruops += app.groups.length; //Count all groups in this app
app.groups.forEach(function(group){
if(group.id===id)
group.name = newname; // replace the name
});
});
Maybe a more succinct sol'n
function changeName(objArray, objId, newName) {
objArray.forEach(function(obj) {
if (obj.id === objId) obj.Name = newName;
});
}
Personally: if this were me, when creating these objects, I would create a new obj and key them by id.
var myApps = {};
myObject.forEach(function(o) {
myApps[o.id] = o;
});
=>
{
"1": {
"Name": "app1",
"id": "1",
"groups": [
{
"id": "test1",
"name": "test group 1",
"desc": "this is a test group"
},
{
"id": "test2",
"name": "test group 2",
"desc": "this is another test group"
}
]
}
}
And then you could just do:
myApps['someId'].name = 'This is my new Name'
Check it out here:
http://jsfiddle.net/qLTB7/40/
it should be if (object["id"] == value) instead of if (object[x] == value) in 7th line of PitaJ answer, so whole function will look like:
function findAndReplace(object, value, replacevalue) {
for (var x in object) {
if (object.hasOwnProperty(x)) {
if (typeof object[x] == 'object') {
findAndReplace(object[x], value, replacevalue);
}
if (object["id"] == value) {
object["name"] = replacevalue;
// break; // uncomment to stop after first replacement
}
}
}
}
if you leave object[x] - function will replace name also for objects with other keys values set to "test1", for example
{"id": "xxx", "name": "test group 1", "desc": "test1"}

Dynamic Mapping using jquery.map()

I have a series of ajax json responses that I need to convert to a common type of array. The issue is that each json response is slightly different.
Here are two examples of responses I might receive:
var contacts = [{ "ContactId" : "1", "ContactName" : "Bob" },{ "ContactId" : "2", "ContactName" : "Ted" }];
var sites = [{ "SiteId" : "1", "Location" : "MN" },{ "SiteId" : "2", "Location" : "FL" }];
I'm trying to write a method that converts either collection to a common type. An example of the above responses converted would look like this:
var convertedContacts = [{ "value" : "1", "text" : "Bob" },{ "value" : "2", "text" : "Ted" }];
var convertedSites = [{ "value" : "1", "text" : "MN" },{ "value" : "2", "text" : "FL" }];
So I'm trying to use the map function of jquery to facilitate this requirement. Although I can't seem to figure out how to dynamically query for the different property values that will exist depending on which json collection I'm passing into the function.
Here is an example of what I'm trying to do:
function ConvertResponse(arrayToConvert, text, value)
{
var a = $.map(arrayToConvert, function(m) {
return "{ \"text\" : "+eval("m."+text)+", \"value\" : "+eval("m."+value)+" }"
});
}
I also tried this:
function ConvertResponse(arrayToConvert, text, value)
{
var a = $.map(arrayToConvert, function(m) {
return "{ \"text\" : " + m.$(text) + ", \"value\" : " + m.$(value) + " }";
});
}
And this is how you would call it:
var convertedContacts = ConvertResponse(contacts, "ContactName", "ContactId");
var convertedSites = ConvertResponse(contacts, "Location", "SiteId");
Unfortunately this does not seem to work in the least.
Like this?
var contacts = [{ "ContactId" : "1", "ContactName" : "Bob" },{ "ContactId" : "2", "ContactName" : "Ted" }];
var sites = [{ "SiteId" : "1", "Location" : "MN" },{ "SiteId" : "2", "Location" : "FL" }];
function convertResponse(response, text, value) {
return $.map(response, function(it) {
return {
value: it[value],
text: it[text]
};
});
}
var convertedContacts = convertResponse(contacts, 'ContactId', 'ContactName');
var convertedSites = convertResponse(sites, 'SiteId', 'Location');

Categories

Resources