I have js array as seen below:
var names = [{name:"high",id:1},{name:"high",id:2},
{name:"low",id:1}, {name:"low",id:2},{name:"medium",id:1},{name:"medium",id:2}];
I need to create another array out of this like this.
var newArr=[{name:high,items:[1,2]},{name:low,items:[1,2]},{name:medium,items:[1,2]}];
Please suggest me how to do that.
Underscorejs based solution
var obj = {};
_.each(names, function (e) {
var o = obj[e.name];
if (o) {
o.items.push(e.id);
} else {
o = {name: e.name, items: [e.id]};
}
obj[e.name] = o;
});
var result = _.map(obj, function (e) {return e;});
Pure js
var obj = {};
for (var i = 0; i < names.length; i++) {
var e = names[i];
var o = obj[e.name];
if (o) {
o.items.push(e.id);
} else {
o = {name: e.name, items: [e.id]};
}
obj[e.name] = o;
}
var result = [];
for (var k in obj) {
if (obj.hasOwnProperty(k)) {
result.push(obj[k]);
}
};
Here is a simple to understand solution without external library.
var newArr = []
for ( var i in names ) {
var exists = findItemInArray(names[i].name,newArr);
if(exists) { // Another item with same name was added to newArray
var items = exists.items.push(names[i].id); // We add the id to existing item
} else { // No other item with same name was added to newArray
var newItem = {name:names[i].name, items:names[i].id};
newArr.push(newItem);
}
}
And I made this function to return the item if it already exists in newArray
function findItemInArray(name,array){
for(var i in array){
if(array[i].name === name){
return array[i];
}
return null;
}
Here's a solution that uses no external libraries:
/**
* Add the given object to the given set.
*
* #param {object} theSet The set to add this object to.
* #param {object} theObject The object to add to the set.
*
* #return {object} theSet, with theObject added to it.
*
* #note Assumes that theObject.name should be the key,
* while theObject.id should go into the value array.
* #note This is an Array.prototype.reduce() callback.
*/
function collect(theSet, theObject) {
if (theSet.hasOwnProperty(theObject.name)) {
theSet[theObject.name].push(theObject.id);
} else {
theSet[theObject.name] = [theObject.id];
}
return theSet;
}
var names = [{name:"high",id:5},{name:"high",id:6},
{name:"low",id:1}, {name:"low",id:2},{name:"medium",id:3},{name:"medium",id:4}],
combinedSet = names.reduce(collect, {}), // This is Step 1
final = [],
key;
// This is Step 2
for (key in combinedSet) {
if (combinedSet.hasOwnProperty(key)) {
final.push(
{
"name" : key,
"items": combinedSet[key]
}
);
}
}
The first step is to group the IDs under the object names. I use Array.prototype.reduce to do this, with the callback collect. The result of that transformation goes into the combinedSet variable.
The second step is to take the set we made in Step 1 and turn it into the final array: make objects using the set's keys as the name member, and use its values as the items member. I can't use reduce like I could before, so I go with a simple for loop. Note that I wrapped things up with a hasOwnProperty check, to guard against the possibility that someone has modified Object.prototype; if I didn't do this, then there might be more items in the set that I hadn't put there, and that would introduce bugs.
You are looking for a grouping function. Try underscoreJs groupBy:
jsFiddle
var names = [{name:"high",id:1},{name:"high",id:2}, {name:"low",id:1}, {name:"low",id:2},{name:"medium",id:1},{name:"medium",id:2}];
console.debug(_.groupBy(names, 'name'));
// Object {high: Array[2], low: Array[2], medium: Array[2]}, where each item in the nested arrays refers to the original object
Related
I have this question and I cannot find the answer:
Create a function called firstAndLast which takes an array and returns an object which has one property. The key of that property should be the first array element and it's value should be the last element in the array. Example:
firstAndLast(["queen", "referee", "cat", "beyonce"]) should return {queen: "beyonce"}.
Some diversity of approaches (admittedly esoteric, but fun!):
function firstAndLast(a, o){
return !(o = {}, o[a.shift()] = a.pop()) || o;
}
console.log(firstAndLast([1,2,3,4,5]));
console.log(firstAndLast(['a','to','z']));
https://jsfiddle.net/brtsbLp1/
And, of course:
function firstAndLast(a, o){
return !(o = o || {}, o[a.shift()] = a.pop()) || o;
}
console.log(firstAndLast(['a','to','z']));
console.log(firstAndLast(['a','to','z'], {a:'nother',obj:'ect'}));
https://jsfiddle.net/brtsbLp1/1/
Another fun one:
function firstAndLast(a){
return JSON.parse('{"'+a.shift()+'":"'+a.pop()+'"}');
}
https://jsfiddle.net/brtsbLp1/2/
That last one will choke on the first being a number (since labels aren't allowed to be numbers only), plus other issues in general. But this should give some food for thought. The other answers are a bit more obvious.
you can specify the key with []
function firstAndLast(arr){
let o = {};
o[arr[0]] = arr[arr.length - 1]; // the key is the first elem, the value the last elem of the array
return o;
}
let a = [1,2,3,4,5]
let b = firstAndLast(a)
function firstAndLast(arr){
var obj = {
}
var length = arr.length;
obj[arr [0]]=arr[length-1] //{queen:beyonce}
return obj
}
var arr = ["queen", "referee", "cat", "beyonce"]
var output = firstAndLast(arr) //{queen:beyonce}
I have this object:
key = {
spawn:{type:1,img:app.assets.get('assets/spawn.svg')},
wall:{type:2,img:app.assets.get('assets/wall.svg')},
grass:{type:3,img:app.assets.get('assets/grass.svg')},
spike:{type:4,img:app.assets.get('assets/spike.svg')},
ground:{type:5,img:app.assets.get('assets/ground.svg')}
};
And I have an array with only types and I need to add the given image to it, the array looks something like this:
[{type:1,image:null},{type:3,image:null},{type:2,image:null},{type:2,image:null},{type:5,image:null}]
Basically I want to loop the array, find the type in the key object and get the given image and save it into the array.
Is there any simple way to do this?
One thing that stands out here for me is the line
...get the given image and save it into the array
I'm assuming this means the original array. I think a better approach would be to map the appropriate keys and values to a new array but I've assumed, for this example, that it's a requirement.
In an attempt to keep the solution as terse as possible and the request for a lodash solution:
_.each(key, function(prop){
_.each(_.filter(types, { type: prop.type }), function(type) { type.image = prop.img });
});
Given the object of keys and an array of objects like so:
var key = {
spawn:{type:1,img:app.assets.get('assets/spawn.svg')},
wall:{type:2,img:app.assets.get('assets/wall.svg')},
grass:{type:3,img:app.assets.get('assets/grass.svg')},
spike:{type:4,img:app.assets.get('assets/spike.svg')},
ground:{type:5,img:app.assets.get('assets/ground.svg')}
};
var arr = [{type:1,image:null},{type:3,image:null},{type:2,image:null},{type:2,image:null},{type:5,image:null}];
We can first create an array of the properties in the object key to make iterating it simpler.
Then loop over the array arr, and upon each member, check with a some loop which image belongs to the member by its type (some returning on the first true and ending the loop).
You can change the forEach to a map (and assign the returned new array to arr or a new variable) if you want the loop to be without side-effects, and not to mutate the original array.
var keyTypes = Object.keys(key);
arr.forEach(function (item) {
keyTypes.some(function (keyType) {
if (key[keyType].type === item.type) {
item.image = key[keyType].img;
return true;
}
return false;
});
});
The smarter thing would be to change the object of the imagetypes so that you could use the type as the accessing property, or create another object for that (as pointed out in another answer).
I'm not sure if this solution is modern, but it does not use any loops or recursion.
object = {
spawn: {type:1, img:app.assets.get('assets/spawn.svg')},
wall: {type:2, img:app.assets.get('assets/wall.svg')},
grass: {type:3, img:app.assets.get('assets/grass.svg')},
spike: {type:4, img:app.assets.get('assets/spike.svg')},
ground: {type:5, img:app.assets.get('assets/ground.svg')}
};
arr = [
{type:1, image:null},
{type:3, image:null},
{type:2, image:null},
{type:2, image:null},
{type:5, image:null}
];
var typeImages = {};
Object.getOwnPropertyNames(object).forEach(function(value){
typeImages[object[value].type] = object[value].img;
});
arr = arr.map(function(value){
return {
type: value.type,
image: typeImages[value.type]
};
});
var key = {
spawn:{type:1,img:app.assets.get('assets/spawn.svg')},
wall:{type:2,img:app.assets.get('assets/wall.svg')},
grass:{type:3,img:app.assets.get('assets/grass.svg')},
spike:{type:4,img:app.assets.get('assets/spike.svg')},
ground:{type:5,img:app.assets.get('assets/ground.svg')}
};
var typesArray = [{type:1,image:null},{type:3,image:null},{type:2,image:null},{type:2,image:null},{type:5,image:null}];
for(var i = 0, j = typesArray.length; i < j; i++)
{
typesArray[i].image = getKeyObjectFromType(typesArray[i].type).img;
}
function getKeyObjectFromType(type)
{
for(var k in key)
{
if(key[k].type == type)
{
return key[k];
}
}
return {};
}
for (var i = 0; i < typesArray.length; i++) {
for (prop in key) {
if (key[prop].type === typesArray[i].type) {
typesArray[i].image = key[prop].img;
}
}
}
It loops through the array ("typesArray"), and for each array item, it go through all the objects in key looking for the one with the same "type". When it finds it, it takes that key object's "img" and saves into the array.
Using lodash (https://lodash.com/):
var key = {
spawn:{type:1,img:app.assets.get('assets/spawn.svg')},
wall:{type:2,img:app.assets.get('assets/wall.svg')},
grass:{type:3,img:app.assets.get('assets/grass.svg')},
spike:{type:4,img:app.assets.get('assets/spike.svg')},
ground:{type:5,img:app.assets.get('assets/ground.svg')}
};
var initialList = [{type:1,image:null},{type:3,image:null},{type:2,image:null},{type:2,image:null},{type:5,image:null}];
var updatedList = _.transform(initialList, function(result, item) {
item.image = _.find(key, _.matchesProperty('type', item.type)).img;
result.push(item);
});
This will go over every item in the initialList, find the object that matched their type property in key and put it in the image property.
The end result will be in updatedList
In underscore, I can successfully find an item with a specific key value
var tv = [{id:1},{id:2}]
var voteID = 2;
var data = _.find(tv, function(voteItem){ return voteItem.id == voteID; });
//data = { id: 2 }
but how do I find what array index that object occurred at?
findIndex was added in 1.8:
index = _.findIndex(tv, function(voteItem) { return voteItem.id == voteID })
See: http://underscorejs.org/#findIndex
Alternatively, this also works, if you don't mind making another temporary list:
index = _.indexOf(_.pluck(tv, 'id'), voteId);
See: http://underscorejs.org/#pluck
Lo-Dash, which extends Underscore, has findIndex method, that can find the index of a given instance, or by a given predicate, or according to the properties of a given object.
In your case, I would do:
var index = _.findIndex(tv, { id: voteID });
Give it a try.
If you want to stay with underscore so your predicate function can be more flexible, here are 2 ideas.
Method 1
Since the predicate for _.find receives both the value and index of an element, you can use side effect to retrieve the index, like this:
var idx;
_.find(tv, function(voteItem, voteIdx){
if(voteItem.id == voteID){ idx = voteIdx; return true;};
});
Method 2
Looking at underscore source, this is how _.find is implemented:
_.find = _.detect = function(obj, predicate, context) {
var result;
any(obj, function(value, index, list) {
if (predicate.call(context, value, index, list)) {
result = value;
return true;
}
});
return result;
};
To make this a findIndex function, simply replace the line result = value; with result = index; This is the same idea as the first method. I included it to point out that underscore uses side effect to implement _.find as well.
I don't know if there is an existing underscore method that does this, but you can achieve the same result with plain javascript.
Array.prototype.getIndexBy = function (name, value) {
for (var i = 0; i < this.length; i++) {
if (this[i][name] == value) {
return i;
}
}
return -1;
}
Then you can just do:
var data = tv[tv.getIndexBy("id", 2)]
If your target environment supports ES2015 (or you have a transpile step, eg with Babel), you can use the native Array.prototype.findIndex().
Given your example
const array = [ {id:1}, {id:2} ]
const desiredId = 2;
const index = array.findIndex(obj => obj.id === desiredId);
you can use indexOf method from lodash
var tv = [{id:1},{id:2}]
var voteID = 2;
var data = _.find(tv, function(voteItem){ return voteItem.id == voteID; });
var index=_.indexOf(tv,data);
Keepin' it simple:
// Find the index of the first element in array
// meeting specified condition.
//
var findIndex = function(arr, cond) {
var i, x;
for (i in arr) {
x = arr[i];
if (cond(x)) return parseInt(i);
}
};
var idIsTwo = function(x) { return x.id == 2 }
var tv = [ {id: 1}, {id: 2} ]
var i = findIndex(tv, idIsTwo) // 1
Or, for non-haters, the CoffeeScript variant:
findIndex = (arr, cond) ->
for i, x of arr
return parseInt(i) if cond(x)
This is to help lodash users. check if your key is present by doing:
hideSelectedCompany(yourKey) {
return _.findIndex(yourArray, n => n === yourKey) === -1;
}
The simplest solution is to use lodash:
Install lodash:
npm install --save lodash
Use method findIndex:
const _ = require('lodash');
findIndexByElementKeyValue = (elementKeyValue) => {
return _.findIndex(array, arrayItem => arrayItem.keyelementKeyValue);
}
If you're expecting multiple matches and hence need an array to be returned, try:
_.where(Users, {age: 24})
If the property value is unique and you need the index of the match, try:
_.findWhere(Users, {_id: 10})
Array.prototype.getIndex = function (obj) {
for (var i = 0; i < this.length; i++) {
if (this[i][Id] == obj.Id) {
return i;
}
}
return -1;
}
List.getIndex(obj);
I got similar case but in contrary is to find the used key based on index of a given object's. I could find solution in underscore using Object.values to returns object in to an array to get the occurred index.
var tv = {id1:1,id2:2};
var voteIndex = 1;
console.log(_.findKey(tv, function(item) {
return _.indexOf(Object.values(tv), item) == voteIndex;
}));
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js"></script>
And If you want some particular key value from an object by id then use
var tv = [{id:1, name:"ABC"},{id:2, name:xyz}]
_.find(tv , {id:1}).value // retrun "ABC"
The simplest question ever, and I did not find right answer yet.
Got object list: object_list = {}
Got object: object_x = {...}
How do I add object_x to object_list[objects_x]?
I tried: object_list[objects_x][object_list[objects_x].length] = object_x, but object_list[objects_x].length is undefined.
push() does not work either.
Do I really need to define external counter for that?
PLEASE NOT THAT I MEAN LIST OF LISTS OF OBJECTS. NOTE THE DIFFERENCE BETWEEN objects_x and object_x.
There is no simple solution like in PHP where you simply $array['something'][] = $somedata ?
object_list['object_x'] = object_x;
// or
object_list.object_x = object_x;
console.log(object_list.object_x === object_list['object_x'])
How to work with objects - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects
When you create a variable like var stuff = {}, you're creating an empty object literal, it has no attributes (properties or methods) other than what it inherits from Object. If you want to keep objects stored in various lists in this object you need to first create those lists.
var stuff = { shelves: [], selectors: [], images: [], additional: [] };
Now you can add whatever you want to those lists as much as you want.
var image = { src: '/path/to/image.jpg' };
stuff.images.push(image);
You can add more lists to stuff whenever like by just setting the new property on stuff.
stuff.some_other_list = []
Hope it helps.
Your base assumption is wrong.
This:
var object_list = {}
Is not a list. It's not an array and you can't reference its items by index, thus it also does not have .length property.
What you are after is a plain array:
var object_list = [];
Now you can push items into it:
object_list.push(object_x);
Edit: based on your comments and edits, I think what you're really after are couple of helper functions:
function AddToList(list, item) {
var counter = 0;
for (var key in list)
counter++;
var key = "item_index_" + counter;
list[key] = item;
}
function GetItemByIndex(list, index) {
var counter = 0;
var existingKey = "";
for (var key in list) {
if (counter == index) {
existingKey = key;
break;
}
counter++;
}
return (existingKey.toString().length > 0) ? list[existingKey] : null;
}
Having those, you can have such a code now:
var mainList = {};
var newItem = { "foo": "bar" };
AddToList(mainList, newItem);
var dummy = GetItemByIndex(mainList, 0)["foo"]; //will contain "bar"
Live test case.
If you are interested use object, not array, you can use like this:
var object_list = {};
var object_x = {'prop1':'val1'};
// add object
object_list.myobj = object_x;
// for access, same scheme.
object_list.myobj.prop1 = 'valX';
// for loop thru
for (var key in object_list) {
var obj = object_list[key];
obj.prop1 = 'valY';
}
I have a variable which is an array and I want every element of the array to act as an object by default. To achieve this, I can do something like this in my code.
var sample = new Array();
sample[0] = new Object();
sample[1] = new Object();
This works fine, but I don't want to mention any index number. I want all elements of my array to be an object. How do I declare or initialize it?
var sample = new Array();
sample[] = new Object();
I tried the above code but it doesn't work. How do I initialize an array of objects without using an index number?
Use array.push() to add an item to the end of the array.
var sample = new Array();
sample.push(new Object());
To do this n times use a for loop.
var n = 100;
var sample = new Array();
for (var i = 0; i < n; i++)
sample.push(new Object());
Note that you can also substitute new Array() with [] and new Object() with {} so it becomes:
var n = 100;
var sample = [];
for (var i = 0; i < n; i++)
sample.push({});
Depending on what you mean by declaring, you can try using object literals in an array literal:
var sample = [{}, {}, {} /*, ... */];
EDIT: If your goal is an array whose undefined items are empty object literals by default, you can write a small utility function:
function getDefaultObjectAt(array, index)
{
return array[index] = array[index] || {};
}
Then use it like this:
var sample = [];
var obj = getDefaultObjectAt(sample, 0); // {} returned and stored at index 0.
Or even:
getDefaultObjectAt(sample, 1).prop = "val"; // { prop: "val" } stored at index 1.
Of course, direct assignment to the return value of getDefaultObjectAt() will not work, so you cannot write:
getDefaultObjectAt(sample, 2) = { prop: "val" };
You can use fill().
let arr = new Array(5).fill('lol');
let arr2 = new Array(5).fill({ test: 'a' });
// or if you want different objects
let arr3 = new Array(5).fill().map((_, i) => ({ id: i }));
Will create an array of 5 items. Then you can use forEach for example.
arr.forEach(str => console.log(str));
Note that when doing new Array(5) it's just an object with length 5 and the array is empty. When you use fill() you fill each individual spot with whatever you want.
After seeing how you responded in the comments. It seems like it would be best to use push as others have suggested. This way you don't need to know the indices, but you can still add to the array.
var arr = [];
function funcInJsFile() {
// Do Stuff
var obj = {x: 54, y: 10};
arr.push(obj);
}
In this case, every time you use that function, it will push a new object into the array.
You don't really need to create blank Objects ever. You can't do anything with them. Just add your working objects to the sample as needed. Use push as Daniel Imms suggested, and use literals as Frédéric Hamidi suggested. You seem to want to program Javascript like C.
var samples = []; /* If you have no data to put in yet. */
/* Later, probably in a callback method with computed data */
/* replacing the constants. */
samples.push(new Sample(1, 2, 3)); /* Assuming Sample is an object. */
/* or */
samples.push({id: 23, chemical: "NO2", ppm: 1.4}); /* Object literal. */
I believe using new Array(10) creates an array with 10 undefined elements.
You can instantiate an array of "object type" in one line like this (just replace new Object() with your object):
var elements = 1000;
var MyArray = Array.apply(null, Array(elements)).map(function () { return new Object(); });
Well array.length should do the trick or not? something like, i mean you don't need to know the index range if you just read it..
var arrayContainingObjects = [];
for (var i = 0; i < arrayContainingYourItems.length; i++){
arrayContainingObjects.push {(property: arrayContainingYourItems[i])};
}
Maybe i didn't understand your Question correctly, but you should be able to get the length of your Array this way and transforming them into objects. Daniel kind of gave the same answer to be honest. You could just save your array-length in to his variable and it would be done.
IF and this should not happen in my opinion you can't get your Array-length. As you said w/o getting the index number you could do it like this:
var arrayContainingObjects = [];
for (;;){
try{
arrayContainingObjects.push {(property: arrayContainingYourItems[i])};
}
}
catch(err){
break;
}
It is the not-nice version of the one above but the loop would execute until you "run" out of the index range.
//making array of book object
var books = [];
var new_book = {id: "book1", name: "twilight", category: "Movies", price: 10};
books.push(new_book);
new_book = {id: "book2", name: "The_call", category: "Movies", price: 17};
books.push(new_book);
console.log(books[0].id);
console.log(books[0].name);
console.log(books[0].category);
console.log(books[0].price);
// also we have array of albums
var albums = []
var new_album = {id: "album1", name: "Ahla w Ahla", category: "Music", price: 15};
albums.push(new_album);
new_album = {id: "album2", name: "El-leila", category: "Music", price: 29};
albums.push(new_album);
//Now, content [0] contains all books & content[1] contains all albums
var content = [];
content.push(books);
content.push(albums);
var my_books = content[0];
var my_albums = content[1];
console.log(my_books[0].name);
console.log(my_books[1].name);
console.log(my_albums[0].name);
console.log(my_albums[1].name);
This Example Works with me.
Snapshot for the Output on Browser Console
Try this-
var arr = [];
arr.push({});
const sample = [];
list.forEach(element => {
const item = {} as { name: string, description: string };
item.name= element.name;
item.description= element.description;
sample.push(item);
});
return sample;
Anyone try this.. and suggest something.
Use array.push() to add an item to the end of the array.
var sample = new Array();
sample.push(new Object());
you can use it
var x = 100;
var sample = [];
for(let i=0; i<x ;i++){
sample.push({})
OR
sample.push(new Object())
}
Using forEach we can store data in case we have already data we want to do some business login on data.
var sample = new Array();
var x = 10;
var sample = [1,2,3,4,5,6,7,8,9];
var data = [];
sample.forEach(function(item){
data.push(item);
})
document.write(data);
Example by using simple for loop
var data = [];
for(var i = 0 ; i < 10 ; i++){
data.push(i);
}
document.write(data);
If you want all elements inside an array to be objects, you can use of JavaScript Proxy to apply a validation on objects before you insert them in an array. It's quite simple,
const arr = new Proxy(new Array(), {
set(target, key, value) {
if ((value !== null && typeof value === 'object') || key === 'length') {
return Reflect.set(...arguments);
} else {
throw new Error('Only objects are allowed');
}
}
});
Now if you try to do something like this:
arr[0] = 'Hello World'; // Error
It will throw an error. However if you insert an object, it will be allowed:
arr[0] = {}; // Allowed
For more details on Proxies please refer to this link:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
If you are looking for a polyfill implementation you can checkout this link:
https://github.com/GoogleChrome/proxy-polyfill
The below code from my project maybe it good for you
reCalculateDetailSummary(updateMode: boolean) {
var summaryList: any = [];
var list: any;
if (updateMode) { list = this.state.pageParams.data.chargeDefinitionList }
else {
list = this.state.chargeDefinitionList;
}
list.forEach((item: any) => {
if (summaryList == null || summaryList.length == 0) {
var obj = {
chargeClassification: item.classfication,
totalChargeAmount: item.chargeAmount
};
summaryList.push(obj);
} else {
if (summaryList.find((x: any) => x.chargeClassification == item.classfication)) {
summaryList.find((x: any) => x.chargeClassification == item.classfication)
.totalChargeAmount += item.chargeAmount;
}
}
});
if (summaryList != null && summaryList.length != 0) {
summaryList.push({
chargeClassification: 'Total',
totalChargeAmount: summaryList.reduce((a: any, b: any) => a + b).totalChargeAmount
})
}
this.setState({ detailSummaryList: summaryList });
}
var ArrayofObjects = [{}]; //An empty array of objects.