I have currently an object which contains a array on which I can iterate.
====== First Step =====
Iterate over an object's attribute instead of the object itself
I am wondering if there's a way to use :
const obj = new YMap();
obj.forEach(...);
instead of
const obj = new YMap();
obj.map.forEach();
EDIT : From VLAZ Comment, I can add this :
this.forEach = function(f) { this.maps.forEach(f);}
In my constructor so my forEach iterate over the maps attribute of my
object and not over my object itself.
===== Second Step =====
Avoid forEach imbrication to parse an object attribute of type Array of Map/List/Array
By extends, if I add a little more complexity on my object so it doesn't have an array but an array of list, is there a way to do :
const obj = new YMap();
obj.forEach(...);
instead of
const obj = new YMap();
obj.maps.foreach( function(map) {
map.forEach( function(item) {
...
}
});
To explain it differently, I wonder if there's a way that exist that allow me to have this data structure :
{
maps : [
[ 'A', 'B' ],
[ 'C', 'D' ],
[ 'E', 'F' ]
]
}
Where I could use the code :
obj.forEach(function(item) { console.log(item) });
that would output :
A B C D E F
without having to iterate over the array of array and then iterate on the items of each array using an imbricated forEach
My object looks like the following :
function YMap() {
this.maps = [new HashMap()];
Object.defineProperty(YMap.prototype, 'length', {get: function() {
...
}});
}
YMap.prototype.add = function() {...}
YMap.prototype.get = function() {...}
[...]
module.exports = YMap;
you can create custom iterable to loop onto object. I have created one using class based approach with help of Symbol.iterator property.
class YMap {
constructor() {
this.maps = [];
}
[Symbol.iterator]() {
let index = 0;
const that = this;
return {
next() {
let value = undefined;
let done = true;
if (index < that.maps.length) {
value = [...that.maps[index++]].join(" ")
done = false;
}
return {
value,
done
};
}
};
}
add(item) {
this.maps.push(item);
}
}
const obj = new YMap();
obj.add([23, 21]);
obj.add([25, 29]);
for (let c of obj) {
console.log(c, );
}
I've got an Object with variable propertie names and im converting it into an array:
var test = Object.getOwnPropertyNames(obj); //[a, b, c]
Now I've got my array of Property names.
The next step I want to take is to turn this array into an Array of objects like this:
newObj= [ { "name": a }, {"name": b} , {"name" : c }]
How can I achieve that?
You can utilize Array.prototype.map - it transforms sequence into a new array by applying a function to each item, which is wrapping to an object with name property in your case:
var names = ["a", "b", "c"];
var newObj = names.map(function(n) { return { name: n }; });
console.log(newObj);
Combining with your getOwnPropertyNames usage, it can look like:
var newObj = Object.getOwnPropertyNames(obj).map(function(n) { return { name: n }; });
Try this (using Object.getOwnPropertyNames itself)
var obj = { a :1, b:2, c:3 };
var output = Object.getOwnPropertyNames(obj).map( function( key ){
return { "name" : obj[ key ] } ;
});
console.log(output);
Simple approach without getOwnPropertyNames function(using Object.keys function):
// obj is your initial object
var newArr = Object.keys(obj).map(function(k) { return { name: k }; });
I have two JS objects which contain some arrays. I'd like to compare the two objects and create a third object, containing arrays only unique to secondObj.
They look like this:
firstObj : {
Jim_Array : [...],
Joe_Array : [...],
Bill_Array : [...]
}
secondObj : {
Bill_Array : [...],
Sam_Array : [...],
Kate_Array : [...],
Jim_Array : [...],
Joe_Array : [...]
}
I'd like to compare the two objects and end up with the following:
thirdObj : {
Sam_Array : [...],
Kate_Array : [...]
}
You can try something like following
var thirdObj = {};
for (var key in secondObj) {
if(!firstObj.hasOwnProperty(key)) {
// In case you need to compare the array additional check will come here
thirdObj[key] = secondObj[key];
}
}
Another way
var thirdObj = {};
for (var key in secondObj) {
if(firstObj[key] === undefined) {
// In case you need to compare the array additional check will come here
thirdObj[key] = secondObj[key];
}
}
You can use Object.keys() with reduce() and check if firstObj has property of secondObj with hasOwnProperty(), if not add to new object.
var firstObj = {Jim_Array : ['...'], Joe_Array : ['...'], Bill_Array : ['...']}
var secondObj = {Bill_Array : ['...'], Sam_Array : ['...'], Kate_Array : ['...'], Jim_Array : ['...'], Joe_Array : ['...']}
var result = Object.keys(secondObj).reduce(function(o, e) {
if(!firstObj.hasOwnProperty(e)) o[e] = secondObj[e];
return o;
}, {});
console.log(result)
A solution using underscore:
var result = _.pick(secondObj, _.difference( _.keys(secondObj), _.keys(firstObj)));
I have the following:
var list = [
{"item":[{a:5, a1:6, a2:7}, {b:3, b1:4, b2:2}]},
{"item":[{a:1, a1:2, a2:3}, {b:4, b1:5, b2:6}]},
{"item":[{a:2, a1:7, a2:4}, {b:3, b1:7, b2:1}]}
];
Assume that I have the variable list above, how can I sort it such that all the immediate objects with the item key in the list are sorted in ascending order based on a key (i.e. "a1" or "b"). Note that it would not change or reorder the list in list[x]["item"], but only the immediate items in list[x].
The standard sort function appears to sort only on keys within objects within arrays, but I want to sort based on a key located in a nested object in an array.
What is the best way to sort this?
So your main issue is that you need to find an object in the internal item array with the matching property. Since you don't know what object it will be located on. Note that a limitation here is that you're always going to be comparing on the first found instance, even if more than one object in item possesses the comparison property. Here goes:
var list = [
{"item":[{a:5, a1:6, a2:7}, {b:3, b1:4, b2:2}]},
{"item":[{a:1, a1:2, a2:3}, {b:4, b1:5, b2:6}]},
{"item":[{a:2, a1:7, a2:4}, {b:3, b1:7, b2:1}]}
];
function comparatorMaker(prop) {
var findVal = function(acc, obj) {
return acc || obj[prop];
};
return function(x, y) {
if (!x.item && !y.item) return 0;
if (x.item && !y.item) return -1;
if (!x.item && y.item) return 1;
var xVal = x.item.reduce(findVal, null) || 0;
var yVal = y.item.reduce(findVal, null) || 0;
return (xVal === yVal) ? 0 : (xVal > yVal) ? 1 : -1;
};
}
var myComparator = comparatorMaker('a');
list.sort(myComparator); // element 1, element 2, element 0
What's happening here is that we generate a unique comparator function for a given property name. It will now work with any:
var myComparator = comparatorMaker('b1');
list.sort(myComparator); // element 0, element 1, element 2
The findVal function that we define when making the comparator function is used with item.reduce. The reduction iterates over the contents of item and returns either the already-found value or looks for the value on the current element under examination. This could be done more efficiently, actually, since we end up iterating every element in item even if we find a match immediately, but it would take more lines of code to demonstrate that so I kept it simple.
The comparator itself should return 1, 0 or -1 depending on whether the resulting values are found to be greater-lesser, equal, or lesser-greater. The first few lines of the comparator function are just to handle cases where elements in list do not actually have the item property, since the way you phrased the question, it sounded like this might sometimes be the case.
Javascript's built-in sort method will do what you want, you just have to pass it the appropriate function (which is the tricky part). You can do it any number of ways really, but one easy way would be by creating a sortBy function that takes the keys, indexes, etc. that you need to get the actual value you want to sort on and returns a comparator function.
Something like this:
function sortBy(key1, index, key2) {
return function(a, b) {
return a[key1][index][key2] - b[key1][index][key2];
}
}
Which you'd then pass to the sort function like this:
list.sort(sortBy("item", 0, "a1"));
Which would sort your particular data structure by a1.
var list = [
{"item":[{a:5, a1:6, a2:7}, {b:3, b1:4, b2:2}]},
{"item":[{a:1, a1:2, a2:3}, {b:4, b1:5, b2:6}]},
{"item":[{a:2, a1:7, a2:4}, {b:3, b1:7, b2:1}]}
];
function sortBy(key1, index, key2) {
return function(a, b) {
return a[key1][index][key2] - b[key1][index][key2];
}
}
list.sort(sortBy("item", 0, "a1"));
for (idx in list) {
document.write("<pre>" + JSON.stringify(list[idx]) + "</pre>");
}
What is the best way to sort this?
If "best" means the most readable, perhaps the Underscore solution will be useful.
How to it works?
Very simple, just extends both object of each array in one and then compare desired properties.
Using Underscore
var list = [
{ "item" :[{ a : 5 , a1 : 6 , a2 : 7 }, { b : 3 , b1 : 4 , b2 : 2 }]},
{ "item" :[{ a : 1 , a1 : 2 , a2 : 3 }, { b : 4 , b1 : 5 , b2 : 6 }]},
{ "item" :[{ a : 2 , a1 : 7 , a2 : 4 }, { b : 3 , b1 : 7 , b2 : 1 }]}
];
/// SORT FUNCTION
function sortList(list, attr) {
return list.sort(function(a, b) {
return _.extend(a.item[0],a.item[1])[attr] > _.extend(b.item[0],b.item[1])[attr];
})
}
var out = sortList(list, "a2");
for (idx in out) {
document.write("<pre>" + JSON.stringify(out[idx]) + "</pre>");
}
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore.js"></script>
No Dependencies
Object.prototype.extend = function(obj) {
for(i in obj)
this[i] = obj[i];
return this;
};
var list = [
{ "item" :[{ a : 5 , a1 : 6 , a2 : 7 }, { b : 3 , b1 : 4 , b2 : 2 }]},
{ "item" :[{ a : 1 , a1 : 2 , a2 : 3 }, { b : 4 , b1 : 5 , b2 : 6 }]},
{ "item" :[{ a : 2 , a1 : 7 , a2 : 4 }, { b : 3 , b1 : 7 , b2 : 1 }]}
];
/// SORT FUNCTION
function sortList(list, attr) {
return list.sort(function(a, b) {
return a.item[0].extend(a.item[1])[attr] > b.item[0].extend(b.item[1])[attr];
})
}
var out = sortList(list, "b2");
for (idx in out) {
document.write("<pre>" + JSON.stringify(out[idx]) + "</pre>");
}
var list = [
{item:[{a:5, a1:6, a2:7}, {b:3, b1:4, b2:2}]},
{item:[{a:1, a1:2, a2:3}, {b:4, b1:5, b2:6}]},
{item:[{a:2, a1:7, a2:4}, {b:3, b1:7, b2:1}]}
];
function srt(base_on){
old_idx=[];
old_srt=[];
new_srt=[];
srt_var=[];
new_list=[];
for(x=0;x<list.length;x++){
for(xx=0;xx<list[x]['item'].length;xx++){
if(list[x]['item'][xx][base_on]){
old_idx.push(x);
old_srt.push(list[x]['item'][xx][base_on]);
new_srt.push(list[x]['item'][xx][base_on]);
}
}
}
new_srt.sort();
for(x=0;x<new_srt.length;x++){
new_list.push(list[old_idx[old_srt.indexOf(new_srt[x])]]);
}
list=new_list;
}
then, just call this
srt('a1'); // to sort by a1 value
happy try ^_^
I was working on a solution to another question posed, and I came up with a solution, but I'm convinced that there's a more elegant way to do it. Let's say that you have an object where all of the values are a string of values separate by commas, like this:
{ "action" : "goto,goto", "target" : "http://www.google.com,http://www.cnn.com" }
But, you'd like to separate the values and break up the object into an array of objects, like this:
[
{ "action" : "goto", "target" : "http://www.google.com" },
{ "action" : "goto", "target" : "http://www.cnn.com" }
]
Here's what my solution was:
var actions = obj.action.split(',');
var targets = obj.target.split(',');
// combined the actions and targets arrays
var combinedData = _.zip(actions, targets);
// go through the combinedData array and create an object with the correct keys
var commandList = _.map(combinedData, function(value) {
return _.object(["action", "target"], value)
});
This does what I want and doesn't look terrible, but is there a slicker way of accomplishing this?
Functional style is great. Here's a more direct approach.
var newObjects = [];
for(var k in o) {
var vals = o[k].split(',');
for(var i = 0, len = vals.length; i < len; i++) {
newObjects[i] = newObjects[i] || {};
newObjects[i][k] = vals[i];
}
}
I wouldn't worry too much about the implementation until you come up with a nice, compact, semantic name for this operation. Any ideas?
So, I did a little refactoring of my code to create a more functional and cleaner looking answer:
var obj = { "action" : "goto,goto", "target" : "http://www.google.com,http://www.cnn.com" }
// separate and split the values form the object
function separate(obj) {
return _.map( _.values( obj ), function(value) {
return value.split(',');
});
}
// returns [[ "goto", "goto"], ["http://www.google.com", "http://www.cnn.com"]]
// call separate and recombine the values with zip
function separateAndRecombine(obj) {
return _.zip.apply(_, separate(obj));
}
// returns [[ "goto", "http://www.google.com"], ["goto", "http://www.cnn.com"]]
// accept an object that has properties with a string of values
// separated by commas, and separate the values to create an array of objects
function unwind(obj) {
return _.map( separateAndRecombine(obj), function(value) {
return _.object(_.keys(obj), value)
});
};
/* returns:
[{ "action" : "goto", "target" : "http://www.google.com" },
{ "action" : "goto", "target" : "http://www.cnn.com" }] */
Now, unwind() will take an object with any number of properties or values and 'unwind' all of the existing properties.