Lets Suppose I have 1000's of objects. Now I want to store objects with same name in an array So that I'll have multiple arrays having objects with same name. How can this be done in JavaScript?
Data can be like this
var input = [
{ name: 'ABC', age: 12 },
{ name: 'XYZ', age: 13 },
{ name: 'ABC', age: 14 },
{ name: 'XYZ', age: 15 },
];
var output = {};
input.forEach(function(obj) {
var array = output[obj.name];
if (!array) {
array = output[obj.name] = [];
}
array.push(obj)
})
for(name in output) {
console.log('There are ' + output[name].length + ' people named ' + name);
}
In javascript, objects aren't copied into arrays. They exist in memory and when added to a an array the reference to that object is what lives in an array.
In the following code, myObj === arr1[0] === arr2. Which means the following is true:
var myObj = {name:'Dave', age: 55};
var arr1 = [myObj];
var arr2 = [myObj];
arr2[0].age = 44;
console.log(myObj.age);
// prints 44
console.log(arr1[0].age);
// prints 44
So to get what you need, you just need to organize your data into arrays. In javascript, you can filter arrays:
// original data
var data = [
{name: 'ABC', age: 12},
{name: 'XYZ', age: 13},
{name: 'ABC', age: 14},
{name: 'XYZ', age: 15},
{name: 'XYZ', age: 16},
];
// this returns a function to be used in Array.filter to filter for objects with the specified name
function nameFilter(name) {
return function(datum) {
return datum.name === name;
}
}
// filter for each type
var abcPeople = data.filter(nameFilter('ABC'));
var xyzPeople = data.filter(nameFilter('XYZ'));
console.log(data.length);
//5
console.log(abcPeople.length);
//2
console.log(xyzPeople.length);
//3
If you run the above code, you would have 3 arrays and all object in abcPeople would also be in data such that any change to one would be reflected in the other. The same is true for xyzPeople. Just to be clear, filter creates a new array, so data is not modified.
UPDATE: Added example where lists are dynamically determined
// original data
var data = [
{name: 'ABC', age: 12},
{name: 'XYZ', age: 13},
{name: 'ABC', age: 14},
{name: 'XYZ', age: 15},
{name: 'XYZ', age: 16},
];
var sortedData = {};
data.forEach(function(datum){
// initializes an array for any unseen name
if(!sortedData[datum.name]) {
sortedData[datum.name] = [];
}
// add the datum to the list for its name
sortedData[datum.name].push(datum);
});
// all names
console.log(Object.keys(sortedData));
// "ABC", "XYZ"
// items named "ABC"
console.log(sortedData['ABC']);
// [{"name": "ABC","age": 12}, {"name": "ABC","age": 14}]
Related
I was wondering if there's a way to create an object with changeable data.
Eg:
pearson = {
name: "",
age: 0
}
Can I do something like a loop that each time it changes these 2 variables and assign the whole object with the data into an array, but each time the object will hold the updated data?
Something like:
let pearson = { name: '', age: 20 }
const pearsonsList = [{name: 'dave', age: 20}, {name: 'jessy', age: 30}]
let arr = []
pearsonsList.forEach((e) =>{
pearson.name = e.name
pearson.age = e.age
arr.push(pearson)
})
console.log(arr[0])
/* this what arr[0] holds
{
"name": "jessy",
"age": 30
}*/
how to make arr[0] have a different value than arr[1] where the object data always get overridden ?
The main problem here is your arr is storing the reference to your pearson object, which gets modified each time you set it, even after you push them into your arr.
A solution would be to construct a new object each time before pushing it in.
const pearsonsList = [{name: 'dave', age: 20}, {name: 'jessy', age: 30}]
let arr = []
pearsonsList.forEach((e) =>{
let pearson = { name: '', age: 20 }
pearson.name = e.name
pearson.age = e.age
arr.push(pearson)
})
An optional, and cleaner solution would be to use .map instead of .forEach too
const pearsonsList = [{name: 'dave', age: 20}, {name: 'jessy', age: 30}]
let arr = pearsonsList.map((e) =>{
let pearson = { name: '', age: 20 }
pearson.name = e.name
pearson.age = e.age
return person;
})
I have a javascript object as follows.
{
name: "tom",
age: 5,
fruits: [
{name: "apple",qty: 4},
{name: "orange",qty: 13},
{name: "banana",qty: 3}
]
}
I am trying to convert this object into an object given below.
{
name: "tom",
age: 5,
apple: 4,
orange: 13,
banana: 3
}
How do I achieve this? I have tried to loop through the fruits array but I am unable to find a way to create a variable with the fruit name and assign the qty to it.
You can use forEach and delete to clean up the old key. Take care not to overwrite keys accidentally, though (you could test if (e.name in obj) as a safety check).
const obj = {
name: "tom",
age: 5,
fruits: [
{name: "apple",qty: 4},
{name: "orange",qty: 13},
{name: "banana",qty: 3}
]
};
obj.fruits.forEach(e => obj[e.name] = e.qty);
delete obj.fruits;
console.log(obj);
you can use below simple code
var b={
name: "tom",
age: 5}
for (var i = 0; i<a.fruits.length; i++) {
b[a.fruits[i].name]=a.fruits[i].qty;
}
This a generic function to convert if you don't want to mutate the original object. Destructure the object to get fruits and rest of the properties separately. Then you can use Object.assign() and map to to create a new object.
let obj = {
name: "tom",
age: 5,
fruits: [
{name: "apple",qty: 4},
{name: "orange",qty: 13},
{name: "banana",qty: 3}
]
}
const converter = ({ fruits, ...rest }) =>
Object.assign(rest, ...fruits.map(({ name, qty }) => ({ [name]: qty })))
console.log(converter(obj))
I have an array of objects and trying to take thevalues inside those objects and push them into an array based on the same property value. So for example.
array = [
{name: 'John', age: 12},
{name: 'Lily', age: 22}
]
I have this array of objects and now I want to iterate through it and create arrays with all name values and age values. The array also needs to be the same name as the values. So the result will be.
name = ['John', 'Lily']
age = [12, 22]
How would I be able to do this?
Just map over the array like so:
const array = [
{name: 'John', age: 12},
{name: 'Lily', age: 22}
]
const name = array.map(e => e.name);
const age = array.map(e => e.age);
console.log(name);
console.log(age);
EDIT
If the array has dynamic objects, you can do this:
const array = [
{name: 'John', age: 12},
{name: 'Lily', age: 22}
];
for (var key in array[0]) {
window[key] = array.map(e => e[key]);
}
console.log(name);
console.log(age);
I have this 2 Arrays representing the same data:
array1 = [
{name: "max", age: 30},
{name: "paul"},
{name: "paul.Jack", age: 25},
{name: "max.David"},
{name: "max.Sylvia", age: 27},
{name: "paul.Jack.Ned"},
{name: "paul.Jack.Mike"},
{name: "max.David.Jeff"},
{name: "max.Sylvia.Anna", age: 5},
{name: "max.David.Buffy"},
{name: "max.Sylvia.Craig"},
{name: "max.Sylvia.Robin"}
];
array2 = [
{
name: "max",
age: 30,
children: [
{
name: "Sylvia",
age: 27,
children: [
{name: "Anna", age: 5},
{name: "Craig"},
{name: "Robin"}
]
},
{
name: "David",
children: [
{name: "Jeff"},
{name: "Buffy"}
]
}
]
},
{
name: "paul",
children: [
{
name: "Jack",
age: 25,
children: [
{name: "Ned"},
{name: "Mike"}
]
}
]
}
];
my objective is to have a function unEven which transform the array1 to the array2, I'm using lodash to do this here's where I'm now:
To unEven array1 to array2 the tracking property in this case 'name' contain the information about where in the new array this item should be pushed check this js bin, this work for 3 level nested array but my goal is to have it unEven arrays without limit of their nesting level, that's where I'm stuck.
The unEven function will be like the concatAll function presented in this video.
Here's the unEven function:
Array.prototype.unEven = function (trackingProperty, children, resultArray) {
var newItem, prop, index, parent, subParent, subParentIndex;
resultArray = resultArray || [];
this.forEach(function (item) {
newItem = lodash.omit(item, trackingProperty);
prop = lodash.pick(item, trackingProperty);
if (prop[trackingProperty].indexOf('.') === -1) {
resultArray.push(item);
} else {
newItem[trackingProperty] = prop[trackingProperty].split(".");
parent = {};
parent[trackingProperty] = newItem[trackingProperty][0];
index = lodash.indexOf(resultArray, lodash.find(resultArray, parent));
if (newItem[trackingProperty].length === 2) {
newItem[trackingProperty] = newItem[trackingProperty][1];
if (!Array.isArray(resultArray[index][children])) {
resultArray[index][children] = [];
}
resultArray[index][children].push(newItem);
} else if (newItem[trackingProperty].length === 3) {
subParent = {};
subParent[trackingProperty] = newItem[trackingProperty][1];
subParentIndex = lodash.indexOf(resultArray[index][children], lodash.find(resultArray[index][children], subParent));
newItem[trackingProperty] = newItem[trackingProperty][2];
if (!Array.isArray(resultArray[index][children][subParentIndex][children])) {
resultArray[index][children][subParentIndex][children] = [];
}
resultArray[index][children][subParentIndex][children].push(newItem);
}
}
});
return resultArray;
};
To give my use case for this I'm trying to make a d3js tree layout of angular ui router in my application that will be generated from the routes JSON file since I make the routes in a JSON file.
Here's a lodash-heavy solution that I think does what you want. You can skip the cloning if you don't care about mutating the original array, and skip the sorting if you always have children after their parents in the original array.
function unEven(array1) {
_(_.clone(array1, true)) //begin chaining syntax, with cloned array
.each(function(person) {
person.name = person.name.split(".") //replace name with array of names
})
.sortBy(function(person) {return person.name.length}) //sort so that we handle children after parents
.reduce(function(result, person) {
var parentArray = result;
var name = person.name.pop() //their actual name is the last one in the list
_.each(person.name, function(parentName) { //loop through parent names to find the proper array to add to
var parent = _.find(parentArray, {name: parentName});
if(!parent) throw new Error(name + " has non-existent parent "+parentName);
parentArray = parent.children = parent.children || []
})
person.name = name; //return name back to just being their name
parentArray.push(person);
return result;
}, []) //reduce ends chaining syntax; so no need for .value
}
I would like a function
combineListOnKeys(listOfObjs, listOfKeys)
that will take this:
var listOfObjs =
[
{ name: john, state: ny, age: 12}
, { name: john, state: ny, age: 22}
, { name: john, state: dc, age: 32}
, { name: john, state: dc, age: 42}
, { name: paul, state: ca, age: 52}
]
var listOfKeys = ["name", "state"]
and returns this:
combineListOnKeys(listOfObjs, listOfKeys)
[
{ "name": john, "state": ny, "age": [12, 22]}
,{ "name": john, "state": dc, "age": [32, 42]}
,{ "name": paul, "state": ca, "age": [52]}
]
I'm essentially looking to match on multiple specified keys that all these objects share, and take the remaining unspecified keys and combine them into a list, thus removing some duplicate information.
I'm using underscore.js, but I cannot find an example of this problem in the docs. Thanks in advance!
Sorry this doesn't conform with your revised requirements for a function but I got started before you revised and put in a lot of effort and I hope this is enough for you to put together your own function. Using underscore's _.reduce and _.each methods in succession (and the _.each can probably be replaced with a second _.reduce, or with _.map -- as usual there's more than one way to do it).
var arr = [
{ name: 'john', state: 'ny', age: 12}
, { name: 'john', state: 'ny', age: 22}
, { name: 'john', state: 'dc', age: 32}
, { name: 'john', state: 'dc', age: 42}
, { name: 'paul', state: 'ca', age: 52}
];
var resultsMap = _.reduce(arr, function(memo, arrEl) {
/*
* var key = JSON.stringify(_.omit(arrEl, 'age'));
*
* From original answer but naively fails to account for Javascript objects not returning in order.
* See "IIFE" below and http://stackoverflow.com/a/28989092/34806
*/
var key = (function() {
var ageOmittedObj = _.omit(arrEl, 'age');
var ageOmittedPairs = _.pairs(ageOmittedObj);
var sortedPairs = _.reduce(_.keys(ageOmittedObj).sort(), function(sortedPairs, key) {
var pair = _.find(ageOmittedPairs, function(kvPair) {return kvPair[0] == key});
sortedPairs.push(pair);
return sortedPairs;
}, []);
return JSON.stringify(sortedPairs)
}) ();
memo[key] = memo[key] || {};
memo[key].ages = memo[key].ages || [];
memo[key].ages.push(arrEl.age);
return memo;
}, {});
var resultsArr = [];
_.each(resultsMap, function(v, k) {
var resultObj = {};
var nameStatePairs = JSON.parse(k);
var nameStateObj = _.object(_.map(nameStatePairs, function(pair){return [pair[0], pair[1]]}));
// compare above to http://stackoverflow.com/a/17802471/34806
resultObj.name = nameStateObj.name;
resultObj.state = nameStateObj.state;
resultObj.age = v.ages;
resultsArr.push(resultObj);
});
console.log(JSON.stringify(resultsArr));
// [{"name":"john","state":"ny","age":[12,22]},{"name":"john","state":"dc","age":[32,42]},{"name":"paul","state":"ca","age":[52]}]
Not in underscore.js, but plain JS. Which should work fine since underscore is a library running on JavaScript.
I would output a new array using array.prototype.map combined with a for loop that test the new array for multiples. Since this is only one dimension deep, we do not need recursion.
var arr = [
{ name: "john", state: "ny", age: 12}
, { name: "john", state: "ny", age: 22}
, { name: "john", state: "dc", age: 32}
, { name: "john", state: "dc", age: 42}
, { name: "paul", state: "ca", age: 52}
]
var arr2d2 = []; //new array that is going to contain the merged values.
arr.map(function(element){
var outerElement = element;
var found = false; //set initially to false. If not found add element to the new array.
for (var i = 0; i < arr2d2.length; i++)
{
if (arr2d2[i].name == outerElement.name && arr2d2[i].state == outerElement.state)
{
found = arr2d2[i]; // save the element.
break; //stop the loop
}
};
if (found)
{
if (found.age != outerElement.age)
{
found.age.push(outerElement.age); //push the age to the new value.
}
}
else
{
outerElement.age = [outerElement.age]; //convert age to an array, like you specified.
arr2d2.push(outerElement); //not found yet. push element;
}
});
document.body.innerHTML += JSON.stringify(arr2d2); //only to display the result. Not part of the solution.