Copy single field of all objects in array in single array - javascript

I wanted to optimize my code removing a for-loop.
groupFieldNames = [];
for (i = 0; i < data.length; i++) {
groupFieldNames.push(data[i].groupFieldName);
}
data is an array of objects, each having 4 fields.
I am interested in the one identified as groupFieldName.
Is there a way to avoid the loop and directly push the fields in the array?
EDIT:
I went with #Yosvel Quintero suggestion (to all the guys suggesting the map solution, he was the first one), and checked the performance.
With a data array having ~60k objects I've got:
3ms using map;
11ms using for-loop
Not bad.

You can use Array.prototype.map()
const groupFieldNames = [];
for (i = 0; i < data.length; i++) {
groupFieldNames.push(data[i].groupFieldName);
}
To:
const groupFieldNames = data.map(o => o.groupFieldName);

You could effectively use Array's built-in .map() here as follows -
var data = [
{ id: 1, groupFieldName: 'abcd' },
{ id: 2, groupFieldName: 'pars' }
];
var groupFieldNames = data.map(obj => obj.groupFieldName)
console.log(groupFieldNames);

You can use map
var groupFieldNames = [];
var data=[{groupFieldName:'a'},{groupFieldName:'b'},{groupFieldName:'c'}]
console.log(data.map(x=>x.groupFieldName))
You can also use forEach
var groupFieldNames = [];
var data=[{groupFieldName:'a'},{groupFieldName:'b'},{groupFieldName:'c'}]
data.forEach(x=>groupFieldNames.push(x.groupFieldName))
console.log(groupFieldNames)

You can use Array.prototype.map() with Destructuring assignment in the following way:
const data = [
{id: 66, groupFieldName: 'test', other: 'other'},
{id: 66, groupFieldName: 'test2', other: 'other2'}
];
const groupFieldNames = data.map(({groupFieldName}) => groupFieldName);
console.log(groupFieldNames);

Related

How to push all the objects inside an array

It will give data by checking for each variant inside the variant array, it show all the object if the condition matched or undefined if not, but in this particular code, it is creating a new array for each item, something like this :-
[{id: 'something'}] [{id: 'something'}] [{id: 'something'}] [{id: 'something'}]
I want it to have all the result inside one array:-
[
{id: 'something'},
{id: 'something'},
{id: 'something'},
{id: 'something'}
]
const mynewarr = [];
const myimages = product_details.data.product.images;
for(var i = 0; i < product_details.data.product.variants.length; i++) {
const myvari = product_details.data.product.variants[i].image_id;
const real = myimages.find(imageid => imageid.id == myvari);
mynewarr.push(real);
}
Just use a destructuring assignment to "unpack" the array before the push.
mynewarr.push(...real);
If I understand correctly you need to go:
const newArray = product_details.data.product.variants.map((variant) => variant.image_id === 'your_condition' ? { id: variant.image_id } : undefined)
The newArray will contain an array of objects with the ids.
Since your myimages is an array of array, you can push the object by accessing the 0th index of the filtered item(using .find).
If there's a possibility that the .find method might return undefined you can add a conditional check to push only the found items.
You can update your code to something like the below.
const mynewarr = [];
const myimages = product_details.data.product.images;
for(var i = 0; i < product_details.data.product.variants.length; i++){
const myvari = product_details.data.product.variants[i].image_id;
const real = myimages.find(imageid => imageid.id === myvari)
if(real){
mynewarr.push(real[0]); //Add only the object and not the sub array.
}
}

Is iterating over a big array of objects the "correct way" for changing/adding values?

I have an array that contains objects with multiple values that could grow from hundreds to thousands of elements that need to be constantly accessed and modified. Something like:
var array = [
{
id: 'someId',
val1: 'someValue',
val2: 'someValue'
},
{...n}
]
In order to change an existing object I'll get it by id while looping through the array
array.forEach(obj => {
if(obj.id == '999'){
obj.value2 = 'someOtherValue'
}
})
I know there are different ways of looping and different methods, for, indexOf, find, etc, I'm not asking which is the best or efficient way, but it seems weird to iterate over a big array that many times.
So, is there another way I could alter a object at a certain location in the array without having to loop every time or it this normal ?
If you wanted to speed things up, you could use an Object rather than an Array.
E.g.
var obj = {
someId: {
val1: 'someValue',
val2: 'someValue'
}, ...
}
This would be quicker as objects can be accessed/amended using obj.someId rather than looping.
First off, for loops are more performant than Iterable.forEach loops.
Secondly, what's stopping you from doing this?
const arr = [];
for (let i = 0; i < 5; i++) {
arr.push({
id: i,
type: '🐕',
sound: 'Bark!'
});
}
console.log(JSON.stringify(arr));
arr[2]['type'] = '🐷';
arr[2]['sound'] = 'Oink!';
console.log(JSON.stringify(arr));
We can do this if we've got an array of objects that increase incrementally. Alright, but maybe we don't know what index it's in - or maybe, our list is unsorted.
let arr = [],
names = ['Waffles', 'Pancake', 'Strawberry', 'Chocolate', 'Biscuit'];
for (let i = 0; i < 5; i++) {
arr.push({
id: i,
name: names[i],
type: '🐕',
sound: 'Bark!'
});
}
console.log(JSON.stringify(arr));
arr = arr.map(animal => {
if (animal.id !== 2) return animal;
animal.type = '🐷';
animal.sound = 'Oink!';
return animal;
});
console.log(JSON.stringify(arr));
That being said, to be even more performant, we should use a for loop. If time is very crucial for you, chances are you're dealing with a super large data set. In that case, I'd recommend switching over to key-value mapped storage: either as a JavaScript object, Sequalise file, Redis database (fast database using RAM) for fast retrieval, or MySQL/Postgres/MariaDB etc. (slightly slower, as it uses storage) for storing super large data sets.
let arr = [],
names = ['Waffles', 'Pancake', 'Strawberry', 'Chocolate', 'Biscuit'];
for (let i = 0; i < 5; i++) {
arr.push({
id: i,
name: names[i],
type: '🐕',
sound: 'Bark!'
});
}
console.log(JSON.stringify(arr));
// You could just start out with storing it as an object, however in this example I'm going to convert my previous array.
// It's best to only do this once, though. If you already have existing data and want to convert it over to an object, I'd recommend doing it like this.
const obj = {};
for (let i = 0; i < arr.length; i++) {
const animal = arr[i];
obj[animal.id] = animal;
}
console.log(JSON.stringify(obj));
obj[3]['type'] = '🐷';
obj[3]['sound'] = 'Oink!';
console.log(JSON.stringify(obj));
// Now, let's convert it back. You probably will never need to do this, though, unless you REALLY need to use array iterators.
// You can always use a for loop with Object.keys(obj) if you ever need to use it as an iterator. Then, you can access properties of obj using obj[key].
console.log(JSON.stringify(Object.values(obj)));

Convert array of strings into an array of objects

I have this JavaScript array:
[ "124857202", "500255104", "78573M104" ]
I want to convert this particular array into an array of objects as shown below:
[
{ name: "124857202" },
{ name: "500255104" },
{ name: "78573M104" }
]
Use Array#map to convert each value into a different value:
var newArr = arr.map(function(value) {
return {name: value};
});
Array#map applies the callback to each element in the array and returns a new array containing the return values of the callback.
I would take a look at the array.map function in javascript.
const mappedArr = arr.map(value => {
return {
name: value
}
})
I want to convert this particular array into an array of objects as
shown below
If you want to change the actual array in place (rather than creating a new array), you can use a for loop to iterate the indexes of your array. For each index, you can replace the value with an object {name: arr[i]}. This object has a name key, and takes a value which is the current element arr[i].
const arr = [ "124857202", "500255104", "78573M104" ];
for(let i = 0; i < arr.length; i++) {
arr[i] = {name: arr[i]};
}
console.log(arr);
Or, if you want to make a new array and leave the original untouched, you can use Felix's answer, here it can be re-written to use more modern ES6 features to make it more concise, such as an arrow function and shorthand property names:
const arr = [ "124857202", "500255104", "78573M104" ];
const res = arr.map(name => ({name}));
console.log(res);
Another approach - Array#reduce.
var arr = ["124857202", "500255104", "78573M104"];
var res = arr.reduce(function(s, a){
s.push({name: a});
return s;
}, [])
console.log(res);
You can use
var arrayOfStrings = ["124857202", "500255104", "78573M104"];
var arrayOfObjects = [];
arrayOfStrings.forEach(function (element, index) {
arrayOfObjects.push({
name: element,
})
});
Felix Kling' answer, gehsekky's answer and the second part of Nick Parsons' answer are the most correct. For completeness, here is a version that uses Underscore's _.map:
import { map } from 'underscore';
var result = map(array, name => ({name}));
For this particular use case, _.map doesn't buy you much compared to Array.prototype.map except for a little bit of added portability. Going the other way, however, is a bit easier on the brain with _.map because of Underscore's iteratee shorthands:
// Underscore map
var array = map(result, 'name');
// Array.prototype.map
var array = result.map(obj => obj.name);
Underscore's map and other collection functions really shine when you need to iterate over a plain object, since JavaScript's built-in methods don't support this at all:
var objectOfStrings = {
first: "124857202",
second: "500255104",
third: "78573M104"
};
// to array of strings, Underscore
var arrayOfStrings = map(objectOfStrings);
// to array of strings, vanilla JS
var arrayOfStrings = [], value;
for (key in objectOfStrings) {
arrayOfStrings.push(objectOfStrings[key]);
}
// to array of objects, Underscore
var arrayOfObjects = map(objectOfStrings, name => ({name}));
// to array of objects, vanilla JS
var arrayOfStrings = [], name;
for (key in objectOfStrings) {
name = objectOfStrings[key];
arrayOfStrings.push({name});
}
var objectOfObjects = {
first: {name: "124857202"},
second: {name: "500255104"},
third: {name: "78573M104"}
};
// to array of strings, Underscore
var arrayOfStrings = map(objectOfStrings, 'name');
// to array of strings, vanilla JS
var arrayOfStrings = [], value;
for (key in objectOfObjects) {
arrayOfStrings.push(objectOfObjects[key].name);
}
// to array of objects, Underscore
var arrayOfObjects = map(objectOfObjects);
// to array of objects, vanilla JS
var arrayOfObjects = [], value;
for (key in objectOfStrings) {
arrayOfObjects.push(objectOfStrings[key]);
}

Removing object from one array if present in another array based on value

Last question did not get well received as was a possible duplicate. Writing again to explain how this is slightly different as can't get the solution I want.
I have an array called _USERS and another one called newArray.
newArray looks like this:
newArray = ["BLRlXKIeWkanHiSCXbBCFRTIaqk1", "sF4gWbZvAMPmrbeHsKzln7LowOx2"]
_USERS is an array of objects and the objects have a property/attribute called useruid which equals a string. How can I remove an object from _USERS if the useruid string matches ANY string found in the newArray.
Solutions I have tried include:
for (var k = 0; k < newArray.length; k++){
if (_USERS[j].useruid == newArray[k]){
_USERS.splice(newArray[k])
}
var result = _.differenceWith(_USERS, newArray, _.isEqual);
neither of these have worked and I just cant quite put my finger on the missing piece
INITIAL _USERS CODE:
console.log(_USERS) => [Object, Object, Object, Object]
Each object has
gender: "male", name: "Rich", username: "rich#rich.com", useruid: "BLRlXKIeWkanHiSCXbBCFRTIaqk1"
newArray = ["BLRlXKIeWkanHiSCXbBCFRTIaqk1", "sF4gWbZvAMPmrbeHsKzln7LowOx2"]
newArray[0] = a string. This string matches the useruid in the Rich object. therefore I would like that to be deleted and then the below to happen
console.log(_USERS) => [Object, Object, Object]
It looks like a simple filter to me:
let filteredUsers = _USERS.filter(u => !newArray.includes(u.useruid))
Here it is in action:
var newArray = ["BLRlXKIeWkanHiSCXbBCFRTIaqk1", "sF4gWbZvAMPmrbeHsKzln7LowOx2"]
var _USERS = [{ gender: "male", name: "Rich", username: "rich#rich.com", useruid: "BLRlXKIeWkanHiSCXbBCFRTIaqk1" }]
let filteredUsers = _USERS.filter(u => !newArray.includes(u.useruid));
/*Printing*/
/*Before*/
document.write("Before: <br>" + JSON.stringify(_USERS) + "<br><br>");
/*After*/
document.write("After <br>" + JSON.stringify(filteredUsers));
Here's a simple solution if I understand your question:
_USERS = _USERS.filter(u => newArray.indexOf(u.useruid)===-1);
There are several clean ways to do this, but just to comment on your splice implementation. Splice expects the first parameter to be an index of an element not an object, so if you call splice(1) then it will delete from the object at index 1 to the end of the array. The second parameter is the number of elements that should be deleted, so splice(1, 1) will delete only the element at index 1. Here is some sample code that may help:
var newArray = ["xyz", "def"];
var _USERS = [
{useruid: "abc"},
{useruid: "def"},
{useruid: "ghi"}
];
for(var i = 0; i < _USERS.length; i++)
{
for(var j = 0; j < newArray.length; j++)
{
if(_USERS[i].useruid == newArray[j])
{
_USERS.splice(i, 1); //remove element at index i
i--; //decrement i because we now removed an element
break; //move to next element
}
}
}
JSFiddle For Reference
To mutate your original array with a loop and Array#splice you need to run your loop in reverse as the length of the array and indexes of items in your array will change when you remove an item, and hence you will miss some of the items. Examples in ES6.
With a forward running loop, incorrect result.
function customRemove(users, unwanted) {
for (let user of users.entries()) {
if (unwanted.includes(user[1].useruid)) {
users.splice(user[0], 1);
}
}
}
const newArray = ['BLRlXKIeWkanHiSCXbBCFRTIaqk1', 'sF4gWbZvAMPmrbeHsKzln7LowOx2'];
const _USERS = [{
useruid: 'BLRlXKIeWkanHiSCXbBCFRTIaqk1'
}, {
useruid: 'BLRlXKIeWkanHiSCXbBCFRTIaqk1'
}, {
useruid: 'BLRlXKIeWkanHiSCXbBCFRTIaqk2'
}, {
useruid: 'BLRlXKIeWkanHiSCXbBCFRTIaqk1'
}];
console.log(JSON.stringify(_USERS));
customRemove(_USERS, newArray);
console.log(JSON.stringify(_USERS));
With a reverse running loop, correct result.
// Generator creates index number in reverse
function* reverseIndexes(arr) {
let key = arr.length - 1;
while (key >= 0) {
yield key;
key -= 1;
}
}
// Generator like Array#entries but in reverse
function* reverseEntries(arr) {
for (let key of reverseIndexes(arr)) {
yield [key, arr[key]];
}
}
function customRemove(users, unwanted) {
// Reversed loop removing unwanted matches with Array#splice
for (let user of reverseEntries(users)) {
if (unwanted.includes(user[1].useruid)) {
users.splice(user[0], 1);
}
}
}
const newArray = ['BLRlXKIeWkanHiSCXbBCFRTIaqk1', 'sF4gWbZvAMPmrbeHsKzln7LowOx2'];
const _USERS = [{
useruid: 'BLRlXKIeWkanHiSCXbBCFRTIaqk1'
}, {
useruid: 'BLRlXKIeWkanHiSCXbBCFRTIaqk1'
}, {
useruid: 'BLRlXKIeWkanHiSCXbBCFRTIaqk2'
}, {
useruid: 'BLRlXKIeWkanHiSCXbBCFRTIaqk1'
}];
console.log(JSON.stringify(_USERS));
customRemove(_USERS, newArray);
console.log(JSON.stringify(_USERS));
Well just to expand on #Denys answer. I have taken the .filter approach and added it to a jsfiddle. I've only included useruid for a user but that should be enough to filter as required.

Sorting object by value

I can imagine this has been asked a few times but I literally cannot find an example of a solution to the specific problem I'm trying to figure out.
So I have an object, like so:
var collection = [{ id: 0 }, { id: 1 }, { id: 2 }];
I then have an array, which is the 'order', like so:
var order = [2, 0, 1];
I want to use the 'order' array to reorder the collection in that specific order. I've been trying quite a few solutions with the .sort function, but I can't find one that fits. Can anyone enlighten me? Probably simple, I'm hoping.
You can use the sort() method to accomplish this using indexOf:
collection.sort(function(a, b){
return order.indexOf(a.id) > order.indexOf(b.id);
});
You can use indexOf function on the order array in the custom sort function, like this:
collection.sort(function(x, y) {
return order.indexOf(x.id) > order.indexOf(y.id);
});
seems to be as easy as that:
var collection = [{ id: 0 }, { id: 1 }, { id: 2 }];
var order = [2, 0, 1];
var sorted = [];
for(var i=0,c=order.length;i<c;i++){
sorted.push(collection[order[i]]);
}
Try that:
var collection = [{ id: 0 }, { id: 1 }, { id: 2 }];
var order = [2, 0, 1];
var sortedCollection = [];
for ( var i = 0; i < order.length; i++ )
sortedCollection.push(collection[order[i]]);
console.log(sortedCollection);
The thing you want to avoid here is scanning through either of these arrays more than you have to.
Here's one solution that avoids this:
/*
* Map the indexes of the objects in collection to their final location
*/
var sortIndex = {};
order.forEach(function(value, index) {
sortIndex[value] = index;
});
/*
* Put the objects in collection into their new, sorted collection
*/
var sortedCollection = [];
collection.forEach(function(value) {
var sortedLocation = sortIndex[value.id];
sortedCollection[sortedLocation] = value;
});
Thus, we have a single scan through each of the arrays, keeping the work down to a minimum.
I've used forEach here as a convenience; you could use a library like Lodash or Underscore, or rewrite this to use explicit iteration over the arrays.

Categories