How to map a javascript array to another javascript array - javascript

I have a constructor in JavaScript which contains 2 properties Key and Values array:
function Test(key, values) {
this.Key = key;
this.Values = values.map(values);
}
Then I created an array of Test objects:
var testObjectArray = [];
testObjectArray.push(new Test(1, ['a1','b1']), new Test(2, ['a1','b2']));
Now I want to map the testObjectArray to single key-value pair array which will be similar to :
[
{ "Key" : "1", "Value" : "a1" },
{ "Key" : "1", "Value" : "b1" },
{ "Key" : "2", "Value" : "a2" },
{ "Key" : "2", "Value" : "b2" },
]
How can I achieve this using array's map function?

I guess you are misunderstanding map(). Here is a very simple example:
a = [1, 2, 3]
b = a.map(function (i) { return i + 1 })
// => [2, 3, 4]
Here is the MDN documentation for map: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map. So you should rethink the usage of map in your case. By the way - your example is not working, because values is not a function.
Here is a possible solution:
res = [];
a = [['a1','b1'],['a1','b2']];
for (var i = 0; i < a.length; ++i) {
for(var j = 0; j < a[i].length; ++j) {
res.push({"Key": i + 1 , "Value" : a[i][j]});
}
}

I'm sure there are other ways, but here's something with plain Javascript that does what you want:
http://jsfiddle.net/KXBRw/
function Test(key, values) {
this.Key = key;
this.Values = values;//values.map(values);
}
function getCombinedTests(testObjectArray) {
var all = [];
for (var i = 0; i < testObjectArray.length; i++) {
var cur = testObjectArray[i];
for (var j = 0; j < cur.Values.length; j++) {
all.push({"Key": ""+cur.Key, "Value": cur.Values[j]});
}
}
return all;
}
var testObjectArray1 = [];
testObjectArray1.push(new Test(1, ['a1','b1']), new Test(2, ['a1','b2']));
var combined = getCombinedTests(testObjectArray1);
console.log(combined);

You could use .reduce(), .concat() and .map() for this.
var result = testObjectArray.reduce(function(res, obj) {
return res.concat(obj.Values.map(function(val) {
return {"Key":obj.Key, "Value":val};
}));
}, []);
Not sure what values.map(values); was supposed to do though.
DEMO: http://jsfiddle.net/BWNGr/
[
{
"Key": 1,
"Value": "a1"
},
{
"Key": 1,
"Value": "b1"
},
{
"Key": 2,
"Value": "a1"
},
{
"Key": 2,
"Value": "b2"
}
]
If you're super strict about not creating unnecessary Arrays, you can tweak it a little and use .push() instead of .concat().
var result = testObjectArray.reduce(function(res, obj) {
res.push.apply(res, obj.Values.map(function(val) {
return {"Key":obj.Key, "Value":val};
}));
return res;
}, []);
DEMO: http://jsfiddle.net/BWNGr/1/

You can achieve this by using the following for each loop where each key value pair will be pushed to an array.
var mapped = [];
$.each(testObjectArray, function(key, value) {
for(x in value.Values) {
mapped.push({
Key: value.Key,
Value: x
});
}
});

Related

How can I check if object exists in array of objects and update quantity?

I have an array objArray. I want to make a function so that it will check if there is another object with the same name key. If it exists, it will add +1 in the qty key. If the object doesn't exist, it will push the new object to the array.
var objArray = [
{"name":"bike","color":"blue","qty":2},
{"name":"boat","color":"pink", "qty":1},
];
var carObj = {"name":"car","color":"red","qty":1};
var bikeObj = {"name":"bike","color":"blue","qty":1};
function checkAndAdd (obj) {
for (var i = 0; i < objArray.length; i++) {
if (objArray[i].name === obj.name) {
objArray[i].qty++;
break;
}
else {
objArray.push(obj);
}
};
}
checkAndAdd(carObj);
console.log(objArray);
checkAndAdd(bikeObj);
console.log(objArray);
After checkAndAdd(carObj);
console.log(objArray);
Should give
[
{"name":"car","color":"red", "qty":1},
{"name":"bike","color":"blue","qty":2},
{"name":"boat","color":"pink", "qty":1},
]
And fter checkAndAdd(bikeObj);
console.log(objArray);
Should give
[
{"name":"car","color":"red", "qty":1},
{"name":"bike","color":"blue","qty":3},
{"name":"boat","color":"pink", "qty":1},
]
Thanks in advance!
You need to check all objects and exit the function if one item is found for incrementing the quantity.
If not found push the object.
var objArray = [{ name: "bike", color: "blue", qty: 2 }, { name: "boat", color: "pink", qty: 1 }],
carObj = { name: "car", color: "red", qty: 1 },
bikeObj = { name: "bike", color: "blue", qty: 1 };
function checkAndAdd (obj) {
for (var i = 0; i < objArray.length; i++) {
if (objArray[i].name === obj.name) {
objArray[i].qty++;
return; // exit loop and function
}
}
objArray.push(obj);
}
checkAndAdd(carObj);
console.log(objArray);
checkAndAdd(bikeObj);
console.log(objArray);
.as-console-wrapper { max-height: 100% !important; top: 0; }
The problem is that you're push()ing inside the loop, instead of returning immediately once found and only call push() outside the loop.
A cleaner approach would be:
function checkAndAdd(obj) {
var matchingObj = objArray.find(o => o.name === obj.name);
if (matchingObj)
matchingObj.qty++;
else
objArray.push(obj);
}
You can also use find to search for the object property.
Using Object.assign before pushing the object will clone the object and will not change the original object when you change the qty (If you add more object with the same name.)
var objArray = [
{"name":"bike","color":"blue","qty":2},
{"name":"boat","color":"pink", "qty":1},
];
var carObj = {"name":"car","color":"red","qty":1};
var bikeObj = {"name":"bike","color":"blue","qty":1};
function checkAndAdd(obj) {
let o = objArray.find(o => o.name === obj.name); //Find if name exist
if (!o) objArray.push(Object.assign({},obj)); //If not exist, push.
else o.qty += obj.qty; //If exist, add the qty
}
checkAndAdd(carObj);
console.log(objArray);
checkAndAdd(bikeObj);
console.log(objArray);
Use findIndex to find in objArray if the object exist.If it does then update the object else push the new object
var objArray = [{
"name": "bike",
"color": "blue",
"qty": 2
},
{
"name": "boat",
"color": "pink",
"qty": 1
},
];
var carObj = {
"name": "car",
"color": "red",
"qty": 1
};
var bikeObj = {
"name": "bike",
"color": "blue",
"qty": 1
};
function checkAndAdd(obj) {
var x = objArray.findIndex(function(item) {
return item.name === obj.name;
});
if (x === -1) {
objArray.push(obj)
} else {
objArray[x].qty = objArray[x].qty + obj.qty
}
}
checkAndAdd(carObj);
checkAndAdd(bikeObj);
console.log(objArray);
Simple enough:
function checkAndAdd(obj) {
for (var i=0; i < objArray.length; i++) {
if (objArray[i]name === obj.name) {
objArray[i].qty++;
return
}
}
objArray.push(obj)
}
Explanation:
Your function was pushing each time the object name didn't match. Instead, when this function a matching name, it incrementes the qty and stops and then if the loops ends without any match, it pushes the obj.

check to see if all objects in an array has a common property

I have an array of objects which I am trying to loop over and check for a common key if it exists for all objects. if the specific key does not exist for all objects I return false.
Here is my code
var x = [{
"item": "alpha",
"value": "red"
}, {
"item": "beta",
"value": "blue"
}, {
"item": "beta",
"value": "gama"
}]
function test(obj) {
var count = 0;
var out = false;
for (var i = 0; i < obj.length; i++) {
if (obj[i].hasOwnProperty('value')) {
count = i;
}
}
if (count == obj.length) {
out = true
}
}
console.log(test(x))
I am getting undefined. Cant figure out what am I missing here
A really simple way to do this is to use Array#every like this
var x = [{
"item": "alpha",
"value": "red"
}, {
"item": "beta",
"value": "blue"
}, {
"item": "beta",
"value": "gama"
}]
function test(obj) {
return obj.every(a => a.hasOwnProperty("value"));
}
console.log(test(x))
Update
As rightfully mentioned by this comment first.
Here can be the simple solution for this object:
var x = [{
"item": "alpha",
"value": "red"
}, {
"item": "beta",
"value": "blue"
}, {
"item": "beta",
"value": "gama"
}];
function test(obj) {
var keyCount = 0;
obj.forEach(function (item, index) {
item.hasOwnProperty('value') && ++keyCount;
});
return keyCount == obj.length;
}
console.log(test(x));
Here is my implementation, which finds every matching key, even nested keys, given a set of objects:
function recurse_obj(obj, cb, _stack = []) {
for (var k in obj) {
cb(k, obj[k], _stack);
if (obj.hasOwnProperty(k) && (obj[k] instanceof Object)) {
_stack.push(k);
recurse_obj(obj[k], cb, _stack);
_stack.pop();
}
}
}
function obj_all_keys(obj) {
var tmp = [];
recurse_obj(obj, (k, v, stack) => {
var ext = (stack.length) ? "." : "";
tmp.push(stack.join(".").concat(ext, k));
});
return tmp;
}
function key_intersection(...objs) {
var lookup = {};
objs.forEach(o => {
obj_all_keys(o).forEach(k => {
if (k in lookup === false)
lookup[k] = 0;
lookup[k]++;
});
});
for (var k in lookup)
if (lookup[k] !== objs.length)
delete lookup[k];
return lookup;
}
Here is the calling code:
var me = { name: { first: "rafael", last: "cepeda" }, age: 23, meta: { nested: { foo: { bar: "hi" } } } };
console.log(key_intersection(me, { name: { first: "hi" } }));
Output: { name: 2, 'name.first': 2 }
The object returned includes only the keys that are found in all the objects, the set intersection, the counts are from book-keeping, and not removed in the callee for performance reasons, callers can do that if need be.
Keys that are included in other nested keys could be excluded from the list, because their inclusion is implied, but I left them there for thoroughness.
Passing a collection (array of objects) is trivial:
key_intersection.apply(this, collection);
or the es6 syntax:
key_intersection(...collection);

How to convert array of object into an array of object with different format?

I'm having an array of object,in which I'm storing the billkey and billvalue as attributes. I want billkey to be the key and billvalue to be the value of that particular key.
var log=[
{
billkey:"Name",
billvalue:"ABC"
},
{
billkey:"Department",
billvalue:"Computer"
}
{
billkey:"Name",
billvalue:"XYZ"
},
{
billkey:"Department",
billvalue:"Electrical"
}];
And I want to convert it into this format:
var log=[
{
Name:"ABC",
Department:"Computer"
},
{
Name:"XYZ",
Department:"Electrical"
}];
How about this simple solution. Hope it helps!
var log=[
{
billkey:"Name",
billvalue:"ABC"
},
{
billkey:"Department",
billvalue:"Computer"
},
{
billkey:"Name",
billvalue:"XYZ"
},
{
billkey:"Department",
billvalue:"Electrical"
}];
var arr = [];
var finalObj = [];
for(var i in log){
var someObject = log[i];
for(var j in someObject){
arr.push(someObject[j]);
}
}
for(var k = 0; k < arr.length; k+=4){
finalObj.push({
Name: arr[k+1],
Department: arr[k+3]
});
}
console.log(finalObj);
create the result using forloop
// store the values
var logs=[];
var log=[
{
billkey:"Name",
billvalue:"ABC"
},
{
billkey:"Department",
billvalue:"Computer"
},
{
billkey:"Name",
billvalue:"XYZ"
},
{
billkey:"Department",
billvalue:"Electrical"
},
];
loop the first array
for (i = 0; i < log.length; i++) {
// create empty variable for storing the values
var index = new Array();
// insert the first index value to key
index[log[i].billkey] = log[i].billvalue
// insert the second index value to key
index[log[i+1].billkey] = log[i+1].billvalue
// insert the result in to new array
logs.push(index);
// increment the i with 1
i=i+1;
}
console.log(logs);
You could use Array#reduce and use the remainder operator as witch for using either the last object or create a new one.
var log = [{ billkey: "Name", billvalue: "ABC" }, { billkey: "Department", billvalue: "Computer" }, { billkey: "Name", billvalue: "XYZ" }, { billkey: "Department", billvalue: "Electrical" }],
result = log.reduce(function (r, a, i) {
var o = {};
if (i % 2) {
r[r.length - 1][a.billkey] = a.billvalue;
} else {
o[a.billkey] = a.billvalue;
r.push(o);
};
return r;
}, []);
console.log(result);

Object Array Formatting

I have an object in this format:
var request = {
"student": [
[
"name",
"age"
],
[
"Tom",
12
],
[
"Jack",
13
]
]
};
I want to transform it into this:
var request = {
"student": [
{
"name": "Tom",
"age": 12
},
{
"name": "Jack",
"age": 13
}
]
}
I tried doing it this way:
var response = [];
var keysCount = req.result[0].length;
var responseCount = req.result.length - 1;
var i = 0,
j = 0,
key;
for (j = 0; j < responseCount; j++) {
for (i = 0; i < keysCount; i++) {
key = req.result[0][i];
response[j][key] = req.result[j + 1][i];
}
}
return response;
But, it is not working as expected.
It's a matter of looping through the first array and creating an array of objects for all the remaining arrays, using values at matching indexes to create properties on object:
var request = {
"student": [
[
"name",
"age"
],
[
"Tom",
12
],
[
"Jack",
13
]
]
};
// Get the header array
var headers = request.student[0];
// Create the new array but mapping the other entries...
var newArray = request.student.slice(1).map(function(entry) {
// Create an object
var newEntry = {};
// Fill it in with the values at matching indexes
headers.forEach(function(name, index) {
newEntry[name] = entry[index];
});
// Return the new object
return newEntry;
});
console.log(newArray);
I would make a small function tabularize that takes an array of data where the first element is an array of headers, and the remaining elements are the rows
Code that follows uses ES6. If you need ES5 support, you can safely transpile this code using a tool like babel.
// your original data
var request = {
"student": [
[
"name",
"age"
],
[
"Tom",
12
],
[
"Jack",
13
]
]
};
// tabularize function
var tabularize = ([headers, ...rows])=>
rows.map(row=>
headers.reduce((acc,h,i)=>
Object.assign(acc, {[h]: row[i]}), {}));
// your transformed object
var request2 = {student: tabularize(request.student)};
// log the output
console.log(request2);
//=> {"student":[{"name":"Tom","age":12},{"name":"Jack","age":13}]}
Or you can create the request object with the intended shape by passing the tabular data directly into the tabularize function at the time of object creation
// tabularize function
var tabularize = ([headers, ...rows])=>
rows.map(row=>
headers.reduce((acc,h,i)=>
Object.assign(acc, {[h]: row[i]}), {}));
// your request object
var request = {
student: tabularize([
[
"name",
"age"
],
[
"Tom",
12
],
[
"Jack",
13
]
])
};
// log the output
console.log(request);
//=> {"student":[{"name":"Tom","age":12},{"name":"Jack","age":13}]}
Let's start off by writing a little function just to create an object from two arrays, one of keys and one of their values:
function makeObjectFromPairs(keys, values) {
var object = {};
for (var i = 0; i < keys.length; i++) {
object[keys[i]] = values[i];
}
return object;
}
// makeObjectFromPairs(['a', 'b'], [1, 2]) === {a: 1, b: 2}
Now we can use the first element of the students array as the keys, and each of the remaining elements as the values.
var keys = students[0];
var result = [];
for (var i = 1; i < students.length; i++) {
result.push(makeObjectFromPairs(keys, students[i]);
}
You could use Array#map etc. as an alternative for the loops, but perhaps this basic approach is more accessible.
Fixing your original code
Since you made a valiant effort to solve this yourself, let's review your code and see where you went wrong. The key point is that you are not initializing each element in your output to an empty object before starting to add key/value pairs to it.
for (j = 0; j < responseCount; j++) {
// Here, you need to initialize the response element to an empty object.
response[j] = {};
Another solution :
var request = {
"student": [
[
"name",
"age"
],
[
"Tom",
12
],
[
"Jack",
13
]
]
};
var response = {};
var students = [];
var responseCount = request.student.length - 1;
var j = 0,
key;
for (j = 0; j < responseCount; j++) {
var student = {};
request.student[0].forEach(function(name, index) {
student[name] = request.student[1 + j][index];
});
students.push(student)
}
response["students"] = students;
console.log(response); // {"students":[{"name":"Tom","age":12},{"name":"Jack","age":13}]}
Lodash solution
var keys = _.head(request.student);
var valueGroups = _.flatten(_.zip(_.tail(request.student)));
var studentObjects = valueGroups.map(function(values){
return values.reduce(function(obj, value, index){
obj[keys[index]] = value;
return obj;
}, {});
});
console.log(studentObjects);
https://jsfiddle.net/mjL9c7wt/
Simple Javascript solution :
var request = {
"student": [
[
"name",
"age"
],
[
"Tom",
12
],
[
"Jack",
13
]
]
};
var students = [];
for(var x = 1; x<request.student.length;x++)
{
var temp = { 'name' : request.student[x][0],
'age' : request.student[x][1]
}
students.push(temp);
}
request = { 'students' : students}
console.log(request);

How to find object by id in array of objects?

I have this json file:
var data = [{
"id": 0,
"parentId": null,
"name": "Comapny",
"children": [
{
"id": 1235,
"parentId": 0,
"name": "Experiences",
"children": [
{
"id": 3333,
"parentId": 154,
"name": "Lifestyle",
"children": []
},
{
"id": 319291392,
"parentId": 318767104,
"name": "Other Experiences",
"children": []
}
]
}
]
}];
I need to find object by id. For example if need to find an object with id:319291392, I have to get:
{"id": 319291392,"parentId": 318767104,"name": "Other Experiences","children": []}
How can I do that?
I tried to use this function:
function findId(obj, id) {
if (obj.id == id) {
return obj;
}
if (obj.children) {
for (var i = 0; i < obj.children.length; i++) {
var found = findId(obj.children[i], id);
if (found) {
return found;
}
}
}
return false;
}
But it doesn't work as it's an array of objects.
If your starting point is an array, you want to invert your logic a bit, starting with the array rather than with the object:
function findId(array, id) {
var i, found, obj;
for (i = 0; i < array.length; ++i) {
obj = array[i];
if (obj.id == id) {
return obj;
}
if (obj.children) {
found = findId(obj.children, id);
if (found) {
return found;
}
}
}
return false; // <= You might consider null or undefined here
}
Then
var result = findId(data, 319291392);
...finds the object with id 319291392.
Live Example
This should work for you:-
var serachById = function (id,data) {
for (var i = 0; i < data.length; i++) {
if(id==data[i].id)
return data[i];
if(data[i].children.length>0)
return serachById(id,data[i].children);
};
return null;
}
console.log(serachById(0,data));
Here is another simple solution using object notation.
This solution will work even if you decide to get rid of teh array and use object notation later on. so the code will remain the same.
It will also support the case when you have element with no children.
function findId(obj, id) {
var current, index, reply;
// Use the object notation instead of index.
for (index in obj) {
current = obj[index];
if (current.id === id) {
return current;
}
reply = findId(current.children, id);
if (reply) {
return reply;
}
// If you reached this point nothing was found.
console.log('No match found');
}
}
console.log(findId(data, 319291392));
do it so:
for (var obj in arr) {
if(arr[obj].id== id) {
console.log(arr[obj]);
}
}

Categories