I have data for example like this:
data: [{
tag: 'Apple',
}, {
tag: 'Microsoft',
}, {
tag: 'Google',
}]
And I want to convert them into like this:
data: ['Apple','Microsoft','Google']
Is there a best way to do this? Wherever I am reading, people are using complex logic using loops. So are there alternative methods to doing this?
One way is to use Array.map and replace the object ele.tag with just the value return ele.tag:
var data =
[{
tag: 'Apple',
}, {
tag: 'Microsoft',
}, {
tag: 'Google',
}];
data = data.map(function(ele){ return ele.tag; });
console.log(data);
Or in ES6 you can simply this even more:
data = data.map(ele => ele.tag);
You could use a for-in loop and push the attribute of the object into an array.
var data = [{
tag: 'Apple',
}, {
tag: 'Microsoft',
}, {
tag: 'Google',
}];
var tags = [];
for (prop in data) {
tags.push(data[prop].tag);
}
console.log(tags);
For easier handling let's take the object in the OP's code and assign it to a variable, as follows:
var obj = {"data":[{"tag":'Apple'},{"tag":'Microsoft'},{"tag":'Google'}]};
var {data}= obj; // object destructing ...
var mapped = data.map(function( e ){ return e.tag});
// re-assigning value of object's data property
obj["data"] = mapped;
console.log(obj); // obj.data now pertains to array of strings
The problem described by the OP involves an object whose data property refers to an array of objects, each with a tag property. The OP inquires as to how to revise the data property so that it refers instead to an array of string values corresponding to each object's tag property.
This example makes use of destructuring to access the array of objects. Then, it uses the array's map() method to access every element's tag property and thereby obtain its string value. The beauty of map() is that it performs iteration behind the scenes sparing the user from having to hand-code a loop with the correct logic -- although in functional programming languages instead of using iteration, recursion is more apt to be utilized for this purpose. Finally, the value of the object's data property is reset to contain the specified array of strings.
Related
I have an array of object which looks like ->
const test - [{id: '1', marks: '32'},{id: '2', marks: '31'},{id: '3', marks: '12'}]
Now, here I am trying to update this array of object so that I want to add one more key value in each object.
setPrevious = test => {
const {
nav: {
queryParams: { bspId }
}
} = stores
const copyTest = _.cloneDeep(test)
this.productCommentsAdded = copyTest?.forEach(marks => {
marks.productId = bspId
})
}
setPrevious(test)
with this, sets the this.productCommentsAdded to undefined . So, what is the proper way to do this ? update it and assign to that variable
forEach does not return anything, so that would cause productsCommentsAdded to always end up as undefined. (If copyTest is undefined, that would also cause this, so that may be another issue to look into.) But assuming that copyTest is defined, one approach is to use map here to achieve what you want, like this:
this.productCommentsAdded = copyTest?.map(marks => {
return {...marks, productId: bspId};
})
This creates a new array, containing a copy of each object in copyTest, (using the object spread operator, which is what the ... part is called), and adds a new property productId to each of those new objects. The original copyTest array objects are unchanged; the new array with the new properties is returned by map and assigned to this.productCommentsAdded.
More info on map: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
If you don't care whether or not the original copyTest array's objects are modified, you can also do this with forEach as follows:
copyTest?.forEach(marks => {
marks.productId = bspId;
})
this.productCommentsAdded = copyTest;
but the first way with map is generally a better practice (less likely to be surprising bugs due to mutating the original array's elements.)
I'm trying to add new elements to an Array but it keeps overwriting it the first element, i'm not sure if i'm doing it correctly, but this is my code:
//name and age contains value from a NgModel
this.data = [
{ "name": this.name, "age": this.age },
];
//Adds them to a new array
this.nArray = [];
this.nArray.push(this.data);
Use concat when you want to merge two arrays.
const nArray = [];
const arr = nArray.concat(this.data);
You can now use the new merged array for your purpose
As it is, you are pushing an array to an empty array. So, there is nothing like overriding here. However, assuming this.nArray is filled with some elements already, you should use the spread syntax for concatenating two arrays like:
this.nArray.push(...this.data);
push method is ok for you. It will add elements at the end of the array. If you have data already setted in your array, then remove this.nArray = [] because this is creating a new empty array, deleting all previous data stored in nArray variable. In any case, if you want to add elements at the beginning try unshift: this.nArray.unshift(this.data);.
If you push data inside nArray you will get an array of array of objects. Maybe you are looking to add only the elements in data and not the whole array. Use concat method for that.
this.nArray.push(this.nArray.concat(data));
Or a shorten syntax using spread operator ...:
this.nArray.push(...data);
NOTE:
I'd recommend you to use const for your array definition and remove the blank assignment of [] in nArray. Also, instead of using concat, use the spread operators with the push method.
Another way to add/insert an element into an array is to use the .splice() method.
With .splice() you can insert a new element at any given index, either overwriting what is currently in that index number, or inserting within, with no overwriting.
Example:
let secretMessage = [ 'Programming', 'is', 'not', 'about', 'what', 'you', 'get',
'easily', 'the', 'first', 'time,', 'it', 'is', 'about', 'what', 'you', 'can',
'figure', 'out.', '-2015,', 'Chris', 'Pine,', 'Learn', 'to', 'Program' ]
read: 'Programming is not about what you get easily the first time, it is about what you can figure out. -2015, Chris Pine, Learn to Program'
secretMessage.splice(6, 5, 'know,');
console.log(secretMessage.join(' '); //log array elements to console, but join them
//with a space (makes it more human legible)
read: 'Programming is not about what you know, it is about what you can figure out. -2015, Chris Pine, Learn to Program'
In this example, at index (position) 6 (starting from 0) we replace the 5 elements from index 6 with the third argument - 'know,'.
If you wanted to insert an element without replacing another, use the same .splice() method but for the second argument, type 0.
Example:
let favDrink = ['I', 'like', 'milkshake.']
favDrink.splice(2, 0, 'banana'); //at index position 2, insert 'banana'.
//***Does not replace 'milkshake'***
console.log(favDrink.join(' ');
read: 'I like banana milkshake.'
Source:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
You know what? You might be reinitializing your array every time.
Try something like this:
// create your new array
this.nArray = [];
// other code
// loop, etc
$.each(row, function(index, data) {
this.data = [
{ "name": this.name, "age": this.age },
];
// now add this element to your array:
this.nArray.push(this.data);
};
Adding the Object in the array...!
Write in this format
let data = [];
data[data.length] = {name:"Aarti",age:22}
data[data.length] = {name:"Saurav",age:23}
console.log(data);
I am running eslint and it is recommended to return a value whenever an arrow function(lambda function) is used. Well that makes sense. However, I come across a case that is hard to walk around.
Dict = {}
Instances = [/* an array of items where items is a dictionary that contains data */]
Instances.map((item) => {
Dict[item.name] = item.url;
});
My goal is to get the data from the Instances array and fill the dictionary Dict with it. I am using the array function to assign key value pair to the dictionary, but that violates the rule of the arrow function.
Is there any iteratools or functions other than map that would help me to achieve the goal, and avoid the rule violation?
Edit: This does not adhere to Airbnb's ES6 Style Guide.
My goal is to get the data from the Instances array and fill the dictionary with it.
Use .reduce
.. and just pass an empty object as the accumulator, filling it up as you iterate through your array.
const instances = [
{ name: 'foo', url: 'https://google.com' },
{ name: 'bar', url: 'https://stackoverflow.com' }
]
const result = instances.reduce((dict, item) => {
dict[item.name] = item.url
return dict
}, {})
console.log(result)
Why not .map?
Array.map always returns a new Array and is meant for mapping each array element to another format.
If your resulting data structure shouldn't be an Array, with the same length as the Array you are operating on, you should avoid using it.
Why .reduce instead of .forEach?
I use forEach only for doing "work" rather than transforming data. Transforming data is almost always achievable with just map and/or reduce.
Here's what I mean by "work":
const users = [userInstance, userInstance, userInstance]
users.forEach(user => user.sendEmail('Hello World'))
Use forEach instead of map.
The point of map is to modify each item in an array and put the modified versions in a new array.
forEach just runs a function on each item.
If you are looking for ES6 solution to fill dictionary object this could help and should pass ESLint also:-
const dict = Instances.reduce((map, obj) => (map[obj.name] = obj.url, map), {});
update
const dict = Instances.reduce((map, obj) => {
let mapClone = {};
mapClone = Object.assign({}, map);
mapClone[obj.name] = obj.url;
return mapClone;
}, {});
I got two Objects
object = {
id: 1,
Oid: 'ff2d344e-77e8-43b3-a6f3-bfba577d6abd',
name: 'Some name'
}
and
object2 = {
id: 3,
array_ref: 'ff2d344e-77e8-43b3-a6f3-bfba577d6abd',
value1: 'Additional Data',
value2: 'Some other additional data'
}
As you see, the only reference between these Objects is the Oid and the Array_ref. Now I want to bind these Objects together to one where the Oid and the Array_ref matches. In the end I have to do this multiple times (with multiple objects).
Is there some easy way to do this?
This Code is realized in JavaScript using angular partly. I'm not able to use anything else.
You are not using arrays (nor JSON) but objects.
If you want to merge two objets, one solution is to use next Javascript API (ES6) Object.assign method through a polyfill (polyfills give you the ability to use standard APIs that are not yet supported):
var obj1 = {
id: 1,
Oid: 'ff2d344e-77e8-43b3-a6f3-bfba577d6abd',
name: 'Some name'
}
var obj2 = {
id: 3,
array_ref: 'ff2d344e-77e8-43b3-a6f3-bfba577d6abd',
value1: 'Additional Data',
value2: 'Some other additional data'
}
var obj3 = Object.assign({}, obj1, obj2);
console.log(obj3);
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.33.3/es6-shim.js"></script>
Which will gives you:
In the above snippet I included a whole es6 polyfill but this polyfill here only contains what you are looking for and is probably better if you want to avoid loading a whole bunch of useless code (I could not easily load it in the snippet).
If you use jQuery or underscore, they also both provides an extend method that you can use instead of a polyfill.
Warning! As you can see, this will actually overwrites any content in obj1 that is also in obj2 with the content of obj2. Here, for example, the resulting object has the id of obj2. If you are looking for a more clever kind of merging, you will need to go for more complicated algorithmic.
If you want to merge only the objects with the same id, I would use underscore:
var objectList = [
{ id: 1, val: "val1", otherVal: "val2" },
{ id: 2, val: "val3" },
{ id: 1, val: "val4", differentVal: "val5" }
];
// group objects by ids
var groups = _.groupBy(objectList, 'id');
// merge the groups
var mergedObjects = _.map(groups, function(objects){
// Adds a new empty object at the beginning of the list
// to avoid modifying the original objects.
// It will be the destination of _.extend.
objects.unshift({});
// use extend with apply so we can provide it an array to be used as arguments
return _.extend.apply(_, objects);
});
console.log(mergedObjects);
<script src="http://underscorejs.org/underscore-min.js"></script>
Notice that some overwriting still can happen (first object's val is overwritten by third object's val here).
Edit: As pointed out in the comment, lodash is likely to be a better solution than underscore. Read here about lodash vs. underscore.
Here's a simple way.
Your object could look like this:
{
'ff2d344e-77e8-43b3-a6f3-bfba577d6abd': {
id: 1,
name: 'Some name'
}
}
And then you access it like this:
object[object2.array_ref]
And you would have all the data you want.
Later on, you can add properties to that object using a for( in ) loop:
var obj = object[object2.array_ref];
for(var k in object2)
{
if( !(k in obj) && object2.hasOwnProperty(k))
{
obj[k] = object2[k];
}
}
This would add the values to the object if they aren't already present.
You could verify other calues by adding conditions to that if.
How can I do something like the following in JS? I would like to imitate .pop() on an object rather than an array.
var deck = {
'cardK' :'13',
'cardQ' :'12',
'cardAJ':'11'
};
var val = deck.pop();
console.log("Key" + val.key );
console.log("Value" + val.val );
It seems like it's not possible.
.pop is only available on an array. In JavaScript, objects (which are essentially associative arrays) are not ordered like an array, so there is no .pop method.
You could use an array:
var deck = [
{ key: 'cardK', val: 13 },
{ key: 'cardQ', val: 12 },
{ key: 'cardAJ', val: 11 },
];
var val = deck.pop();
console.log('key: ' + val.key);
console.log('aa: ' + val.val);
As suggested by other answers, the best solution here might be to use an array of objects. However you could also create your own pop function that removes a key from an object, for example:
function pop(obj) {
var key = Object.keys(obj).pop();
var result = {key: key, val: obj[key]};
delete obj[key];
return result;
}
var val = pop(deck);
You could add a similar pop function to Object.prototype so that you could do deck.pop(), but I would strongly recommend against that type of design.
You are right, it's not possible. See objects as maps or hash tables, rather than "associative arrays". The properties don't have an order and thus a method such as .pop would not make sense (unless of course it would remove a random property, like Python's dictionaries).
If you want to to use .pop and val.key and val.val, you have to create an array of objects instead:
var deck = [
{key: 'cardK', val: '13'},
{key: 'cardQ', val: '12'},
{key: 'cardAJ', val: '11'}
];
As I'm sure you know, .pop is a prototypal Array method, so you can't use it with Javascript objects.
Calling .pop on an array will remove the last element from the array. However, there isn't a "last" key-value pair with objects, as their order is not ever guaranteed. Despite this, if you don't care about order, you could implement a .pop-like function for use with objects, though, again, it wouldn't remove and return the final key-value pair.
Something like this should do the trick:
function pop(obj) {
for (var key in obj) {
var val = obj[key];
delete obj[key];
return {
'key' : key,
'val' : val,
};
};
};
Combined with your code:
var val = pop(deck);
console.log('key: ' + val.key);
console.log('aa: ' + val.val);
When working with this structure, which can be thought of as an associative array, you need to use different techniques. Things like pop(), slice() and even .length will not work as they do with numeric keyed arrays.
I use string keyed object arrays when searching for the key/value pair needs to happen fast.
Here's a jsPef I just created which shows the benefit of your array structure:
http://jsperf.com/bmcgin-object-array-tests (keep in mind the performance goes way up as the array gets bigger)
Also keep in mind the value can be a number, a string, an array, a function, an object ect...