Concatenate multiple object property values into one - javascript

If I have object with following structure:
var test = {
property1: "value1",
property2: "value2",
property3: "value3",
property4: "value4",
property5: "value5"
}
Assuming that property names are fixed and not always in this order, what is the most elegant way to convert this object into following one:
var test_copy = {
prop1Copy: "value1",
propConcat: "value2, value3, value4, value5"
}

I don't think there's any particularly elegant way to do this.
Since your input data has a small number fixed keys there's barely any point using a loop, so this works:
function munge(o) {
return {
prop1Copy: o.property1,
propConcat: [o.property2, o.property3, o.property4, o.property5].join(', ')
}
}

Try this:
function concatObject(object, levels){
var currentLevel = 0;
var newObj = {propConcat: ""};
for(var prop in object){
if(currentLevel < levels){
newObj[prop] = object[prop];
}
else{
newObj["propConcat"] += object[prop];
}
}
}
concatObject(test, 1) would give you the answer, however it would keep the same property name for the variables. You need some kind of function of mapping if you want to change the actual property names (example: from property1 to prop1copy)
This would transform property# to property#copy:
function concatObject(object, levels){
var currentLevel = 0;
var newObj = {propConcat: ""};
for(var prop in object){
if(currentLevel < levels){
newObj[prop+"copy"] = object[prop];
}
else{
newObj["propConcat"] += object[prop];
}
}
}

Im not sure what you need to accomplish here. But if you want copy first item and concat all other take a look at this.
function concatValues (obj) {
var resObj = {prop1Copy: ""}, count = 0, mergedArr = [];
for (var k in obj) {
count == 0 ? resObj.prop1Copy = obj[k] : mergedArr.push(obj[k]);
count++;
}
resObj.propConcat = mergedArr.join(", ");
return resObj;
}
Hope this helps

Here is a more generic solution that would work on a wider range of input with some caveats.
function concatenateObjectValues(obj) {
//If you want the output to be sorted differently, you need to provide your own sort order. This sorts by alphabetical order
var keys = Object.keys(test).sort();
//assuming the first property would always be the copy
//removing the first element and returning it
var copyProp = keys.unshift();
//generate an array that has the values of the remaining properties from the input
var concatProp = keys.reduce(function(memo, key) {
memo.push(test[key]);
return memo;
}, []);
//create `propConcat` and combine the values using the specified separator
var newObj = {
propConcat: concatProp.join(", ")
};
//add the `prop1Copy` property. The first part of the name would be derived from the actual first property .
newObj[copyProp + "Copy"] = obj[copyProp];
return newObj;
}
Assuming you want your concatenated properties in alphabetical order,
the above would work. If not, then you would need to specify a
different sort order. This can be passed in as an argument, if it's going to vary).
if the copy property is going to vary, then this code might also need to change. Also, something that can be passed in as a parameter - trivial if it's just the index, but if you have to look them up by name (e.g., if you want to say "prop1" regardless of where it is., you need to also implement that).
if the names propConcat and prop1Copy need to vary more than that, the logic needs to be implemented. Or the values passed in...
there is no validation. I kept it simple for the sake of the example, but some error handling would be good.
To be honest, if your expected output is going to vary by more than one thing, for example, if you need the copy property to be different and the sort order to be different, then it might just be better to scrap this function. Big variations in the expected input/output make it a bit unwieldy, if you need to pass in most of the stuff to construct the result.

Related

Add a key to an object with keys of an existing array with objects

I've got an array of objects array = [object1, object2, ...], each of them has some keys object1 = { key1: 'value1', ... }. I want to add a key this way:
$rootScope.array[i].newKey = 'someValue'
But angular tells me that $rootScope.array[i] is undefined.
What I've noticed from console is that the objects get the new key but the console still says the same.
You should use less than and not less or equal than comparator.
$scope.init = function () {
for (i = 0; i < /* not <= */ $rootScope.meatTypes.length; i++) {
console.log("I am showing the meatypes:");
console.log($rootScope.meatTypes);
$rootScope.meatTypes[i].counter = '0';
counterOperations.setCounters(i, 0);
}
$rootScope.total = 0;
counterOperations.setTopCounter(0);
};
because when i equals $rootScope.meatTypes.length then $rootScope.meatTypes[i] is undefined.
You are trying to access a member of the array that does not exist.
You need to create a new object and push it onto the array:
$rootScope.array.push({'key1': 'someValue'});
You did not mention lodash, but when I see someone encounter an issue like this, I want to offer the recommendation of using lodash (or underscore.js).
With lodash, you would do something like so, using _.set, which defensively protects against your described issue by automatically adding the necessary elements in the path:
_.set($rootScope, ['array', i, 'newKey'], 'someValue');
This library, properly utilized, solves many issues that you can have with setting and getting variables, ase well as other super useful tools. It has been a major life-saver (and time-saver) for us on our projects.
Like this you can add
$rootScope.array[i] = {}; // first we should create an object on that array location
$rootScope.array[i]['newKey'] = 'someValue'; // then only we can add values
EDIT:
$scope.init = function () {
for (i = 0; i <= $rootScope.meatTypes.length; i++) {
console.log("I am showing the meatypes:");
console.log($rootScope.meatTypes);
**// This is needed**
$rootScope.meatTypes[i]={};// here we should tell that metaType[newItem] is an object other wise it treat it as undefined
$rootScope.meatTypes[i].counter = '0';
counterOperations.setCounters(i, 0);
}
$rootScope.total = 0;
counterOperations.setTopCounter(0);
};

Find index of object in array by key

I have an array of objects like so
myobj= [{"item1" : info in here},{"item2" : info in here}, {"item3" : info in here}]
I'm trying to modify one, but I only know its key. I need to pinpoint the item1 object so I can change its value (the values are random and I don't know them, so I can't rely upon them).
If I could just get the index of the item it would be pretty easy: myobj[index].value = "newvalue".
Maybe using the index isn't the best way, so if it isn't, I'm open to other ideas.
I was thinking I could try something like
myobj.objectVar
Where objectVar is the key I'm being passed (item1, for example), however this does not work, possibly because it's a variable? Is it possible to use a variable like this maybe?
If it helps, I'm using underscore.js as well.
Your guess at a solution doesn't work because you're not accessing the individual objects, you're accessing an array of objects, each of which has a single property.
To use the data in the format you've got now, you need to iterate over the outer array until you find the object that contains the key you're after, and then modify its value.
myobj= [{"item1" : info in here},{"item2" : info in here}, {"item3" : info in here}]
function setByKey(key, value) {
myObj.forEach(function (obj) {
// only works if your object's values are truthy
if (obj[key]) {
obj[key] = value;
}
});
}
setByKey('item1', 'new value');
Of course, the far better solution is to stop using an array of single-property objects, and just use one object with multiple properties:
myobj= {"item1" : info in here, "item2" : info in here, "item3" : info in here};
Now, you can simply use myObject.item1 = "some new value" and it will work fine.
You can write a function like,
function getElementsHavingKey(key) {
var objectsHavingGivenKey = [];
//loop through all the objects in the array 'myobj'
myobj.forEach(function(individualObject) {
//you can use 'hasOwnProperty' method to find whether the provided key
// is present in the object or not
if(individualObject.hasOwnProperty(key)) {
// if the key is present, store the object having the key
// into the array (many objects may have same key in it)
objectsHavingGivenKey.push(individualObject);
}
});
// return the array containing the objects having the keys
return objectsHavingGivenKey;
}
If you only want to get the index of elements having the given key
You can do something like this,
function getIndexesOfElementsHavingKey(key) {
var objectsHavingGivenKey = [];
//loop through all the objects in the array 'myobj'
myobj.forEach(function(individualObject, index) {
//you can use 'hasOwnProperty' method to find whether the provided key
// is present in the object or not
if(individualObject.hasOwnProperty(key)) {
//push index of element which has the key
objectsHavingGivenKey.push(index);
}
});
// returns the array of element indexes which has the key
return objectsHavingGivenKey;
}
Try this code:
function changeObj( obj, key, newval )
{
for( var i=0, l=obj.length; i<j; i++)
{
if( key in obj[i] )
{
obj[i] = newval;
return;
}
}
}
var myObjArray= [{"item1" : "info in here"},{"item2" : "info in here"}, {"item3" : "info in here"}]
To find and add new value to the object inside an array:
myObjArray.forEach(function(obj) {
for(var key in obj) {
// in case you're matching key & value
if(key === "item1") {
obj[key] = "update value";
// you can even set new property as well
obj.newkey = "New value";
}
}
});
You can access objects the same using their index, even the object inside the original object.
Is this kind of what your looking for:
var otherObj = [{"oitem":"oValue"}];
var myobj= [{"item1" : otherObj},{"item2" : "2"}, {"item3" : "tesT"}];
myobj[0].item1[0].oitem = "newvalue";
alert(myobj[0].item1[0].oitem);

Can I loop through a javascript object in reverse order?

So I have a JavaScript object like this:
foo = {
"one": "some",
"two": "thing",
"three": "else"
};
I can loop this like:
for (var i in foo) {
if (foo.hasOwnProperty(i)) {
// do something
}
}
Which will loop through the properties in the order of one > two > three.
However sometimes I need to go through in reverse order, so I would like to do the same loop, but three > two > one.
Question:
Is there an "object-reverse" function. If it was an Array, I could reverse or build a new array with unshift but I'm lost with what to do with an object, when I need to reverse-loop it's properties. Any ideas?
Thanks!
Javascript objects don't have a guaranteed inherent order, so there doesn't exist a "reverse" order.
4.3.3 Object An object is a member of the type Object. It is an unordered collection of properties each of which contains a primitive
value, object, or function. A function stored in a property of an
object is called a method.
Browsers do seem to return the properties in the same order they were added to the object, but since this is not standard, you probably shouldn't rely on this behavior.
A simple function that calls a function for each property in reverse order as that given by the browser's for..in, is this:
// f is a function that has the obj as 'this' and the property name as first parameter
function reverseForIn(obj, f) {
var arr = [];
for (var key in obj) {
// add hasOwnPropertyCheck if needed
arr.push(key);
}
for (var i=arr.length-1; i>=0; i--) {
f.call(obj, arr[i]);
}
}
//usage
reverseForIn(obj, function(key){ console.log('KEY:', key, 'VALUE:', this[key]); });
Working JsBin: http://jsbin.com/aPoBAbE/1/edit
Again i say that the order of for..in is not guaranteed, so the reverse order is not guaranteed. Use with caution!
Why there is no one has mentioned Object.keys() ?
you can get Array of Object's properties ordered as it is, then you can reverse it or filter it as you want with Array methods .
let foo = {
"one": "some",
"two": "thing",
"three": "else"
};
// Get REVERSED Array of Propirties
let properties = Object.keys(foo).reverse();
// "three"
// "two"
// "one"
// Then you could use .forEach / .map
properties.forEach(prop => console.log(`PropertyName: ${prop}, its Value: ${foo[prop]}`));
// PropertyName: three, its Value: else
// PropertyName: two, its Value: thing
// PropertyName: one, its Value: some
There is no way to loop through an object backwards, but if you recreate the object in reverse order then you are golden! Be cautions however, there is nothing that says the order of the object will stay the same as it changes and so this may lead to some interesting outcome, but for the most part it works...
function ReverseObject(Obj){
var TempArr = [];
var NewObj = [];
for (var Key in Obj){
TempArr.push(Key);
}
for (var i = TempArr.length-1; i >= 0; i--){
NewObj[TempArr[i]] = [];
}
return NewObj;
}
The just do the swap on your object like this-
MyObject = ReverseObject(MyObject);
The loop would then look like this-
for (var KeysAreNowBackwards in MyObject){
alert(MyObject[KeysAreNowBackwards]);
}
This answer is similar to a couple of the others, but some users might find the code below easier to copy-paste for their own uses:
Object.keys(foo).reverse().forEach(function(key) { console.log(foo[key]) });
For an object "foo" as described in the question, this code will output the object elements in reverse order: "else", "thing", "some"
You can use
Object.keys
One thing to take care of is that it returns a sorted list of keys (if the keys are numerical). You might need to change it accordingly.
a = {'d':'stack','l':'overflow','b':'out','a':'first','z':'empty'}
out = Object.keys(a).reverse()
console.warn("When key contains characters : "+out)
a = {'1':'stack','4':'overflow','2':'out','5':'first','3':'empty'}
out = Object.keys(a).reverse()
console.warn("When key is a numerical string : "+out)

JavaScript: Get first and only property name of object

If I want to enumerate the properties of an object and want to ignore prototypes, I would use:
var instance = { ... };
for (var prop in instance) {
if (instance.hasOwnProperty(prop)) {
...
}
}
What if instance only has one property, and I want to get that property name? Is there an easier way than doing this:
var instance = { id: "foobar" };
var singleMember = (function() {
for (var prop in instance) {
if (instance.hasOwnProperty(prop)) {
return prop;
}
}
})();
Maybe Object.keys can work for you. If its length returns 1, you can use yourObject[Object.keys[0]] to get the only property of the object. The MDN-link also shows a custom function for use in environments without the keys method1. Code like this:
var obj = {foo:'bar'},
kyz = Object.keys(obj);
if (kyz.length === 1){
alert(obj[kyz[0]]); //=> 'bar'
} else {
/* loop through obj */
}
1 Some older browsers don't support Object.keys. The MDN link supplies code to to make it work in these browsers too. See header Compatibility in the aforementioned MDN page
Shortest form:
instance[Object.keys(instance)[0]];
ES6+ function:
let first = v => v[Object.keys(v)[0]];
Use the function:
first({a:'first', b:'second'}) // return 'first'
var foo = {bar: 1};
console.log(Object.keys(foo).toString());
which will print the string
"bar"
Though my answer is downvoted, it's still worth to know that there is no such thing as order of keys in javascript object. Therefore, in theory, any code build on iterating values can be inconsistent. One approach could be creating an object and to define setter which actually provides counting, ordering and so on, and provide some methods to access this fields. This could be done in modern browsers.
So, to answer you question, in general you approach is still most closs-browser. You can iterate using lodash or any other modern framework wich will hide "hasOwnProperty" complexity from you. As of August'15 Object.keys can be accepted as cross-browser and universal. After all IE8 happened years ago. Still there are some cases when you just don't wont store all set of keys in array. But I'd go with Object.keys - it's more flexible compared to iteration.
Unfortunately, there is no, "list properties" function built in, and there certainly isn't a "getFirstProperty" (especially since there is no guarantee that any property will consistently be "first").
I think you're better off writing a function like this one:
/**
* A means to get all of the keys of a JSON-style object.
* #param obj The object to iterate
* #param count maximum length of returned list (defaults to Infinity).
*/
function getProperties( obj, count )
{
if( isNaN( count ) ) count = Infinity
var keys = []
for( var it in obj )
{
if( keys.length > count ) break;
keys.push( it );
}
return keys;
}
Then, you could access the name though:
instance = {"foo":"bar"}
// String() on an array of < 2 length returns the first value as a string
// or "" if there are no values.
var prop = String(getProperties(instance, 1));
This is an old post, but I ended up writing the following helper function based on Object.keys().
It returns the key and value of the first property.
getFirstPropertyKeyAndValue(sourceObject) {
var result = null;
var ownProperties = Object.keys(sourceObject);
if (ownProperties.length > 0) {
if (ownProperties.length > 1) {
console.warn('Getting first property of an object containing more than 1 own property may result in unexpected results. Ordering is not ensured.', sourceObject);
}
var firstPropertyName = ownProperties[0];
result = {key: firstPropertyName, value: sourceObject[firstPropertyName]};
}
return result;
}
Answers in here all good, and with the caveat that the order may be unreliable (although in practice it seems the order the properties are set tends to stay that way), this quick and dirty method also works:
var obj = {foo: 1, bar: 2};
for(var key in obj) {
//you could use key here if you like
break;
}
//key now contains your first key
or a shorter version should also do it:
for(var key in obj) break;
//key now contains your first key

In Javascript, given value, find name from Object literal

I'm new JavaScript and trying to find out an easier way to find name given a value from object literal.
e.g.
var cars ={ Toyata: ['Camry','Prius','Highlander'],
Honda: ['Accord', 'Civic', 'Pilot'],
Nissan: ['Altima', 'Sentra', 'Quest']};
Given 'Accord', I want to get Honda from the object Cars.
You would need to loop through, like this:
function getManufacturer(carName) {
for(var key in cars) {
if(cars.hasOwnProperty(key)) {
for(var i=0; i<cars[key].length; i++) {
if(cars[key][i] == carName) return key;
}
}
}
return "Not found";
}
You can test it out here, for the same of working cross-browser, this ignores the existence of .indexOf() since IE doesn't have it...that version would look like this:
function getManufacturer(carName) {
for(var key in cars) {
if(cars.hasOwnProperty(key) && cars[key].indexOf(carName) != -1) {
return key;
}
}
return "Not found";
}
If you're going to be doing this once, then use a function like the one given by Bobby. If you're going to be doing this multiple times then I'd suggest creating a reverse mapping of cars to manufacturers:
var manufacturers = {};
// create a map of car models to manufacturers:
for (var manf in cars) {
/* see note below */
for (var i=0; i<cars[manf].length; i++) {
manufacturers[cars[manf][i]] = manf;
}
}
// Now referencing the manufacturers is
// a very fast hash table lookup away:
var model = 'Accord';
alert(manufacturers[model]);
note for those with itchy downvoting fingers: For objects that don't inherit anything as given in the OP a hasOwnProperty check here is unnecessary. For objects that do inherit it depends on the programmer. If you want composability via inheritance then a hasOwnProperty check is exactly what you DONT want. If you don't care about inheritance then use a hasOwnProperty check but if so you would not be inheriting in the first place which would make a hasOwnProperty check unnecessary. In the rare case where you are forced to create the object via inheritance but don't want to check the parent's attributes then you should do a hasOwnProperty check. Of course, if you use a library like Prototype.js that insists on modifying the Object object then I feel sorry for you because you are forced to do a hasOwnProperty check.
Maintain a separate mapping of models to manufacturers.
var cars ={ Toyata: ['Camry','Prius','Highlander'],
Honda: ['Accord', 'Civic', 'Pilot'],
Nissan: ['Altima', 'Sentra', 'Quest']};
var models = {};
var hasOwnProperty = Object.prototype.hasOwnProperty;
for (key in cars) {
if (hasOwnProperty.call(cars, key)) {
var i=0,l=cars[key].length,manufacturer=cars[key];
while (i<l) {
if ( ! hasOwnProperty.call(models, manufacturer)) {
models[manufacturer] = key;
} else {
// Throw an error, or change the value to an array of values
}
i++;
}
}
}

Categories

Resources