I'm trying to find a way to move an object element to a specific position.
For example, I've this object :
{
"element1" : {} // object,
"element2" : {},
"element3" : {}
}
And I search to move element3 at the first position :
{
"element3" : {},
"element1" : {},
"element2" : {}
}
Thanks for your help !
JavaScript objects don't have ordering. You should use an array of objects instead.
var arr = [
{ id: 'element1' },
{ id: 'element2' },
{ id: 'element3' }
]
You could then reorder it something like:
var first = arr.splice(0, 1);
arr.push(first);
Maybe you could then grab specific elements based on id:
var out = arr.filter(function (el) {
return el.id === 'element1';
});
Here's my code for doing that logic.
Thanks!
function _moveElementObject(object, from, to) {
var newObjects = [];
var newObject = {};
var oldObject = {};
var firstObject = {};
var lastObject = {};
var toMoveKey = "";
var toMoveValue;
oldObject = object;
var objLength = _countProperties(oldObject);
var keyNo = 1;
for (var key in oldObject) {
if (keyNo == from) {
toMoveKey = key;
toMoveValue = oldObject[key];
}
keyNo++;
}
console.log(oldObject);
keyNo = 1;
for (var key in oldObject) {
if (keyNo < to) {
firstObject[key] = oldObject[key];
newObject[key] = firstObject[key];
}
keyNo++;
}
console.log(firstObject);
keyNo = 1;
for (var key in oldObject) {
if (to <= objLength) {
lastObject[key] = oldObject[key];
}
keyNo++;
}
delete lastObject[toMoveKey];
newObject[toMoveKey] = toMoveValue;
for (var key in lastObject) {
newObject[key] = lastObject[key];
}
console.log(newObject);
console.log("push");
return newObject;
}
var sampleObj = {
"element1" : {} // object,
"element2" : {},
"element3" : {}
};
_moveElementObject(sampleObj,3,1);
// output object,
{
"element3" : {},
"element1" : {},
"element2" : {},
}
Objects in JavaScript are essentially hash maps. Their properties don't have any ordering, per se. They are simply name value pairs.
You are probably confusing objects with arrays, in which case ordering does indeed matter.
Related
I have a requirement where I have an object like obj={ 'a.b.c' : d }
and I would like it to get converted to {a:{b:{c:d}}}
Is there any way I can achieve this in JavaScript?
Here's a solution (EDITED: code is more complex than before but it gives the result you want, let me know if something doesn't work):
var obj = {
'a.b.c': 22,
'a.b.d.e': 42
}
var newObj = {};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
var keyList = key.split('.');
newObj = generateNewObject(keyList, keyList.length - 1, newObj, obj[key]);
}
}
console.log(newObj);
function generateNewObject(keys, index, existingObj, value) {
if (index < 0) {
return value;
}
var lastKey = keys[index--];
var existingProperty = getProperty(existingObj, lastKey);
if (existingProperty != null && !objectsAreEqual(existingProperty, value)) {
var valueKey = keys[index + 2];
existingProperty[lastKey][valueKey] = value[valueKey];
value = existingProperty;
} else {
var subObj = {};
subObj[lastKey] = value;
value = subObj;
}
return generateNewObject(keys, index, existingObj, value);
}
function objectsAreEqual(obj1, obj2) {
for (var key in obj1) {
if (obj1.hasOwnProperty(key)) {
var prop = getProperty(obj2, key);
if (prop == null) {
return false;
}
}
}
return true;
}
function getProperty(obj, keyDesired) {
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
if (key === keyDesired) {
return obj;
} else {
var prop = getProperty(obj[key], keyDesired);
if (prop != null) {
return prop;
}
}
}
}
return null;
}
I don't know why you would have an object named that way, but this code will do the trick for each key in an object. This will not work correctly on nested objects such as {'a' : { 'b' { 'c' : {{'d' : 'e'}}}}}. You would have to repeat the for-loop part each time the value is a JavaScript object.
EDIT
I modified the code so it recognizes when two properties are the same such as the example { 'a.b.c' : 22 }, 'a.b.c.d.e' : 42. Sorry if it is hard to go through, but basically the generateNewObject method is the real meat of it. The two functions below it are just helper methods.
Array.reduce mostly is a good choice when it comes to handling/transforming of more complex data structures. An approach that solves the given problem generically whilst taking edge cases into account then might look similar to the next provided example ...
var
d = 'd',
q = 'q',
obj = {
'i.k.l.m.n.o.p' : q,
'a.b.c' : d,
'foo' : 'bar',
'' : 'empty'
};
function parseIntoNestedTypes(type) {
return Object.keys(type).reduce(function (collector, integralKey) {
var
nestedType = collector.target,
fragmentedKeyList = integralKey.split('.'),
nestedTypeRootKey = fragmentedKeyList.shift(),
nestedTypeEndValue = collector.source[integralKey];
if (fragmentedKeyList.length === 0) {
nestedType[nestedTypeRootKey] = nestedTypeEndValue;
} else {
nestedType[nestedTypeRootKey] = fragmentedKeyList.reduce(function (collector, key, idx, list) {
var
partialType = collector.partialType || collector.type;
if (idx < (list.length - 1)) {
partialType[key] = {};
} else {
partialType[key] = collector.value;
}
collector.partialType = partialType[key];
return collector;
}, {
value : nestedTypeEndValue,
type : {}
}).type;
}
return collector;
}, {
source: type,
target: {}
}).target;
}
console.log('parseIntoNestedTypes :: type', JSON.stringify(obj));
console.log('parseIntoNestedTypes :: nestedType', JSON.stringify(parseIntoNestedTypes(obj)));
console.log('parseIntoNestedTypes :: type, nestedType : ', obj, parseIntoNestedTypes(obj));
I have a array of object
var arr =
[
{"shares":50,"comments":10},
{"likes":40,"shares":30},
{"comments":10}
];
I want to convert it to
var arr =
[
{"shares":50,"comments":10,"likes":0},
{"likes":40,"shares":30,"comments":0},
{"comments":10,"likes":0,"shares":0}
]
Properties are not fixed numbers and names would be different see another example
var arr2 = [{"a":1},{"b":2},{"c":3},{"d":4},{"e":5},{"f":6}]
to
var arr2 = [{"a":1,"b":0,"c":0,"d":0,"e":0,"f":0},{"a":0,"b":1,"c":0,"d":0,"e":0,"f":0},{"a":0,"b":0,"c":1,"d":0,"e":0,"f":0},{"a":0,"b":0,"c":0,"d":1,"e":0,"f":0},{"a":0,"b":0,"c":0,"d":0,"e":1,"f":0},{"a":0,"b":0,"c":0,"d":0,"e":0,"f":1}]
I can do by iterating all elements of array and keys of every element but I don't know that, is it best way?
Is there any inbuilt function in JavaScript or jQuery?
You can use http://api.jquery.com/jquery.extend/
var defaults = { "shares" : 0, "comments" : 0, "likes" : 0 };
arr = $.map( arr, function( item ){
return $.extend( {}, defaults, item );
});
http://jsfiddle.net/L74q3ksw/
Edit re: updated question
Now it's a matter of building the defaults object which, as I understand, has all the unique keys from all the elements in your array.
So, given
var arr2 = [{"a":1},{"b":2},{"c":3},{"d":4},{"e":5},{"f":6}]
you need to extract "a", "b", "c", "d"... etc and create the defaults.
var defaults = {};
// collect all the keys and set them with value = 0 in defaults
arr2.forEach( function( item ){
Object.keys( item ).forEach( function( key ){
defaults[ key ] = 0;
});
});
// same as the previous solution
arr2 = $.map( arr2, function( item ){
return $.extend( {}, defaults, item );
});
http://jsfiddle.net/7dtfzg2f/2/
It looks like you want
var set = {}; // it will be cleaner with ES6 Set
$.each(arr, function(_,e){
for (var k in e) set[k] = 1;
});
$.each(set, function(k){
$.each(arr, function(_,e){
if (e[k]===undefined) e[k] = 0;
});
});
Demonstration
With pure JavaScript:
var defaults = { "shares": 0, "comments": 0, "likes": 0 };
var arr = [{"shares":50,"comments":10},{"likes":40,"shares":30},{"comments":10}];
arr.slice().map(function(e) {
for (var key in defaults) {
e[key] = e[key] || defaults[key];
}
return e;
});
This keeps you original array as it was. If you want to change your original array you can do following:
var defaults = { "shares": 0, "comments": 0, "likes": 0 };
var arr = [{"shares":50,"comments":10},{"likes":40,"shares":30},{"comments":10}];
arr.forEach(function(e) {
for (var key in defaults) {
e[key] = e[key] || defaults[key];
}
});
You can get the default values from the array with following snippet:
var defaults = arr.reduce(function(m,v) {
for (var key in v) {
m[key] = 0;
}
return m;
}, {});
Just add the key with value, if it not exists:
$(function() {
var arr = [{"shares":50,"comments":10},{"likes":40,"shares":30},{"comments":10}];
$.each(arr, function(idx, obj) {
if (typeof obj.shares === 'undefined') {
obj.shares = 0;
}
if (typeof obj.comments === 'undefined') {
obj.comments = 0;
}
if (typeof obj.likes === 'undefined') {
obj.likes = 0;
}
arr[idx] = obj;
});
console.log(arr);
});
Building on what #dusky said, if you don't actually know what columns will be coming in, you can make a list of columns as a string set. Also assumes you just want to edit the existing array, not make a new one, and use ES6.
// get all keys added to a list that cannot take duplicates
const columnNames = new Set<string>();
arr.forEach(element => {
Object.keys(element)
.forEach(x => columnNames.add(x));
});
// create default with nulls, can replace with 0 or anything here
const defaultKeys = {};
columnNames.forEach(x => {
defaultKeys[x] = null;
});
// Add all missing keys into each object
arr.forEach((element) => {
for (const key in defaultKeys) {
element[key] = element[key] || defaultKeys[key];
}
});
I have this array:
["userconfig", "general", "name"]
and I would like it to look like this
data_structure["userconfig"]["general"]["name"]
I have tried this function:
inputID = "userconfig-general-name"
function GetDataByID(inputID){
var position = '';
for (var i = 0; i < inputID.length; i++) {
var hirarchy = inputID[i].split('-');
for (var index = 0; index < hirarchy.length; index++) {
position += '["'+ hirarchy[index] +'"]';
}
}
return data_structure[position];
}
while hirarchy is the array. I get the [position] as a string which is not working well.
how can I make a js function which builds the object path dynamically by an array?
var arr = ["userconfig", "general", "name"];
var dataStructure = arr.reduceRight(function (value, key) {
var obj = {};
obj[key] = value;
return obj;
}, 'myVal');
Ends up as:
{ userconfig : { general : { name : 'myVal' } } }
Note that you may need a polyfill for the reduceRight method: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/ReduceRight
The below function will take an object to modify and an array filled with the properties needed:
function objPath(obj,path){
path.forEach(function(item){
obj[item] = {};
obj = obj[item];
});
}
var myobj = {};
objPath(myobj,["test","test2","test3"]);
console.log(myobj);
//outputs
Object {test: Object}
test: Object
test2: Object
test3: Object
The function loops over the array creating the new object property as a new object. It then puts a reference to the new object into obj so that the next property on the new object can be made.
JSFiddle
Recursive function
var array = ["userconfig", "general", "name"];
function toAssociative(array) {
var index = array.shift();
var next = null;
if (array.length > 0) {
next = toAssociative(array);
}
var result = new Array();
result[index] = next;
return result;
}
Just curious how this would be accomplished in Javascript? Lets say I have an object such as
var obj = {
'foo.bar.baz': 'valueA',
'foo.bar.qux': 'valueB'
};
How can I iteratively turn these into a nested object such as
console.log(obj.foo.bar.baz); // valueA
console.log(obj.foo.bar.qux); // valueB
It would be something like this I think?
var ret=[];
for (var key in obj)
{
var parts = key.split('.');
for (var i in parts)
{
if (parts.hasOwnProperty(i))
{
// do something?
}
}
ret.push(something);
}
An alternative version:
var obj = {
'foo.bar.baz': 'valueA',
'foo.bar.qux': 'valueB'
};
var obj2 = {};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
var parts = key.split('.');
var head = obj2;
var limit = parts.length - 1;
for (var i = 0; i < limit; i++) {
var part = parts[i];
head = head[part] || (head[part] = {});
}
head[parts[limit]] = obj[key];
}
}
obj2 // =>
{
foo: {
bar: {
baz: "valueA",
qux: "valueB"
}
}
}
Once you have the string (i.e. 'foo.bar.baz'), you can recursively call a function which creates a new object;
Example:
function buildObject(treeElements, value)
{
var object = {};
if(treeElements.length == 1)
{
object[treeElements.shift()] = value;
}
else
{
object[treeElements.shift()] = buildObject(treeElements, value);
}
return object;
}
Simply pass it the array from your split() and the final value it should have.
I have problem with nested object in javascript. I want to generate, lets say, tree of objects. For example I have tree like this:
var tree = {
item1: {
item11: {},
item12: {}
},
item2: {
item21: {
item211: {},
item212: {}
}
}
}
Now I have path in string (like item1.item11) and I want to put item111 to tree object using path.
After calling treePush function I want this:
var tree = {
item1: {
item11: {
item111: {}
},
item12: {}
},
item2: {
item21: {
item211: {},
item212: {}
}
}
}
For now I have this piece of code, but this puts new item into root of tree not into desided level:
//use example: treePush('item1.item11', 'item111', tree);
function treePush(path, value, tree) {
var branch = getBranch(path, tree);
branch[value] = {};
$.extend(tree, branch);
return tree;
}
function search(key, tree) {
//searches key in tree and generates path like 'item1.item11'
}
function getBranch(path, tree) {
var keys = path.split('.'),
obj = tree,
branch = {};
for(var i = 0; i < keys.length - 1; i++) {
var key = keys[i];
if (obj[key] === undefined) {
return {};
}
branch[key] = obj[key];
obj = obj[key];
}
return branch;
};
I think the problem is in line #5 of treePush function (branch[value] = {};) but I can't make it working. Any help appreciated.
Use this:
Object.byString = function(o, s) {
s = s.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
s = s.replace(/^\./, ''); // strip a leading dot
var a = s.split('.');
while (a.length) {
var n = a.shift();
if (n in o) {
o = o[n];
} else {
return;
}
}
return o;
}
Object.byString(tree, 'item1.item11')['item111'] = {};
jsFiddle working example: http://jsfiddle.net/ehE8X/
Object.byString found here.
As you stated, you want to select the path 'item1.item11' and push in there the given 'item111'. For this to work, you either have to specify the key/value to push, or just give it an object and mix that in the given path. The mixin approach requires jQuery for the $.extend method, which I don't like very much (to depend on jQuery for this simple task).
So here are both versions.
jQuery mixin version
var tree = {
item1: {
item11: {},
item12: {}
},
item2: {
item21: {
item211: {},
item212: {}
}
}
};
function treePush (tree, path, item) {
var key, branch = tree;
path = path.split('.');
while (path.length) {
key = path.shift();
branch = branch[key] = branch[key] || {};
}
$.extend(branch, item);
}
treePush(tree, 'item1.item11', {item111: 'value'});
console.log(tree.item1.item11.item111 === 'value');
Specify target key in the path
var tree = {
item1: {
item11: {},
item12: {}
},
item2: {
item21: {
item211: {},
item212: {}
}
}
};
function treePush (tree, path, value) {
var key, branch = tree;
path = path.split('.');
while (path.length > 1) {
key = path.shift();
branch = branch[key] = branch[key] || {};
}
branch[path.shift()] = value;
}
treePush(tree, 'item1.item11.item111', 'value');
console.log(tree.item1.item11.item111 === 'value');