How to get the indices of the objects in this array / JS - javascript

If I have an array of objects:
myArray[person{}, person{}, person{}]
And each person can contain an array of Children objects like this:
person{
name: 'XXX',
age: 'XXX',
children: [{
name: 'XXX',
age: 'XXX'
},{
name: 'XXX',
age: 'XXX'
},{
name: 'XXX',
age: 'XXX'
}]
}
How can I get the index of each Person in myArray and also the index of the objects in the Children array?
I'm getting the index of the Person objects in myArray like this, using indexOf(), which is working:
function getObjectIndex(myObject) {
var myArray = _.flatten(_.values(objects));
var ret = myArray.indexOf(myObject);
return ret; //RETURNS 0, 1, 2 etc...
}
I'm unsure how to expand the functionality of getObjectIndex to get the indices of the Children objects in each Person
function getObjectIndex(myObject) {
var myArray = _.flatten(_.values(objects));
var ret = myArray.indexOf(myObject);
if (myObject.children.length > 0){
//UNSURE WHAT LOGIC TO APPLY HERE
ret += ;
}
return ret;
}
If there are any children objects present, I ideally would like getObjectIndex to return:
Person index in myArray _ Children index in Person
So if there are three Children object in a Person:
0_0
0_1
0_2
Any help or suggestions would be very much appreciated.

If you pass an array to map then the second parameter to the iterator function is the index of the object. This can be used to get the result you want:
var indexArrays = _.map(myArray, function(person, personIndex){
return _.map(person.children, function(child, childIndex){
return personIndex + '_' + childIndex;
});
});
var indices = _.flatten(indexArrays);

Related

JavaScript Replacing Object in Array with ID Number

So I have a series of objects that are pulled from an API and inputted into an array, something like such:
array = [
{id: 0, name: "First", relationship: "Friend"},
{id: 1, name: "Second", relationship: "Friend"}
]
The user is allowed to add and remove objects to the list freely (they will appear within a Vue.JS DataTable), and said user is allowed a maximum of 4 objects within the array (lets say 4 "friends")
How should I go about implementing a function that searches the existing array (say, if its populated from the API), and inputs the new object with the corresponding ID that is missing (so if the user deletes the object with the id 2, and adds another, it will search said array with objects, find the missing id 2 slot in the array, and input the object in its place)?
Previously I have gone about it via implement array.find() with conditionals to see if the array contains or does not contain the certain id value, however, it searches through each entry and can end up inserting the same object multiple times. Another method I haven't attempted yet would be having a separate map that contains ids, and then when a user removes an object, having it correspond with the map, and vice versa when adding.
Any suggestions? Thanks
Instead of an array, I'd keep an object in data. Have it keyed by id, like this:
let objects = {
0: { id: 0, name: 'name0', relationship: 'relationship0' },
1: { id: 1, name: 'name1', relationship: 'relationship1' },
}
Integer keys in modern JS will preserve insertion order, so you can think of this object as ordered. The API probably returns an array, so do this...
// in the method that fetches from the api
let arrayFromApi = [...];
this.objects = array.reduce((acc, obj) => {
acc[obj.id] = obj; // insertion order will be preserved
return acc;
}, {});
Your UI probably wants an array, so do this (refer to "array" in the markup):
computed: {
array() {
return Object.values(this.objects);
},
To create a new object, insert it in order, minding the available keys. Note this is a linear search, but with small numbers of objects this will be plenty fast
methods: {
// assumes maxId is const like 4 (or 40, but maybe not 400)
createObject(name, relationship) {
let object = { name, relationship };
for (let i=0; i< maxId; i++) {
if (!this.objects[i]) {
object.id = i;
this.objects[i] = object;
break;
}
}
try this,
let array = [
{id: 0, name: "First", relationship: "Friend"},
{id: 4, name: "Second", relationship: "Friend"},
{id: 2, name: "Second", relationship: "Friend"},
]
const addItem = (item) => {
let prevId = -1
// this is unnecessary if your array is already sorted by id.
// in this example array ids are not sorted. e.g. 0, 4, 2
array.sort((a, b) => a.id - b.id)
//
array.forEach(ob => {
if(ob.id === prevId + 1) prevId++
else return;
})
item = {...item, id: prevId + 1 }
array.splice(prevId+1, 0, item)
}
addItem({name: "x", relationship: "y"})
addItem({name: "a", relationship: "b"})
addItem({name: "c", relationship: "d"})
console.log(array)
You can simply achieve this with the help of Array.find() method along with the Array.indexOf() and Array.splice().
Live Demo :
// Input array of objects (coming from API) and suppose user deleted 2nd id object from the array.
const arr = [
{id: 0, name: "First", relationship: "Friend" },
{id: 1, name: "Second", relationship: "Friend" },
{id: 3, name: "Fourth", relationship: "Friend" }
];
// find the objects next to missing object.
const res = arr.find((obj, index) => obj.id !== index);
// find the index where we have to input the new object.
const index = arr.indexOf(res);
// New object user want to insert
const newObj = {
id: index,
name: "Third",
relationship: "Friend"
}
// Insert the new object into an array at the missing position.
arr.splice(index, 0, newObj);
// Output
console.log(arr);

How to filter few properties of an object which is in Array of objects if one property equals property from another object

I have a object which has some properties for one user, and I have array of objects which is returned from API.
My goal is to check which object of Array of objects has the same property as the one single initial object, and then it should return only part of it's properities.
I have tried to use .map on Array of objects but it seems not workig.
Below is the code example. I have also prepared codesandbox if You wish.
const user =
{
name: "jan",
lastName: "kowalski",
fullName: "jan kowalski",
car: "audi"
}
;
const usersAnimal = [
{
name: "jan",
lastName: "kowalski",
fullName: "jan kowalski",
animal: "cat",
animalSize: "small",
animalName: "Bat"
},
{
name: "john",
lastName: "smith",
fullName: "john smith",
animal: "dog",
animalSize: "middle",
animalName: "Jerry"
},
{
name: "Anna",
lastName: "Nilsson",
fullName: "Anna Nilsson",
animal: "cow",
animalSize: "big",
animalName: "Dorrie"
}
];
const filtered = usersAnimal.map((userAnimal)=>userAnimal.fullName === user.fullName && return userAnimal.animalName & userAnimal.animalSize & userAnimal.animal);
thanks
https://codesandbox.io/s/admiring-edison-qxff42?file=/src/App.js
For case like this, it would be far easier if you filter it out first then proceed using map:
const filtered = usersAnimal
.filter((animal) => animal.fullName === user.fullName)
.map(({ animalName, animalSize, animal }) => {
return {
animalName,
animalSize,
animal
};
});
I am providing a for loop solution as I haven't learnt many array methods in javascript.
For me the simplest option is to use a for loop and an if check to loop through the arrays values to check for included values.
for (let v in usersAnimal) {
if (usersAnimal[v].fullName === user.fullName) {
console.log(usersAnimal[v])
}
}
The code above will log the entire usersAnimal object containing the fullname we are looking for.
{
name: 'jan',
lastName: 'kowalski',
fullName: 'jan kowalski',
animal: 'cat',
animalSize: 'small',
animalName: 'Bat'
}
commented for further understanding
for (let v in usersAnimal) {
//loops though the array
if (usersAnimal[v].fullName === user.fullName) {
//when the index value 'v' has a fullname that matches the user fullname value
// it passes the if check and logs that object value
return console.log(usersAnimal[v])
//return true...
}
//return null
}
//etc
If you want to filter, I recommend you to use filter.
The map method will create a new array, the content of which is the set of results returned by each element of the original array after the callback function is operated
const user = {name:"jan",lastName:"kowalski",fullName:"jan kowalski",car:"audi"};
const usersAnimal = [{name:"jan",lastName:"kowalski",fullName:"jan kowalski",animal:"cat",animalSize:"small",animalName:"Bat"},{name:"john",lastName:"smith",fullName:"john smith",animal:"dog",animalSize:"middle",animalName:"Jerry"}];
// Get an array of matching objects
let filtered =
usersAnimal.filter(o => o.fullName === user.fullName);
// You get the filtered array, then you can get the required properties
filtered.forEach(o => {
console.log(
'animal:%s, animalSize:%s, animalName:%s',
o?.animal, o?.animalSize, o?.animalName
);
});
// Then use map to process each element
filtered = filtered.map(o => {
const {animal, animalSize, animalName} = o;
return {animal, animalSize, animalName};
});
console.log('filtered', filtered);

Remove empty object from array of objects

I have an array of objects and a delete function that pass the index as a parameter but fails to remove the empty object. Objects containing properties can be removed. Does anyone know how to fix it? The example code is shown below.
let array = [
{
id: '1',
name: 'sam',
dateOfBirth: '1998-01-01'
},
{
id: '2',
name: 'chris',
dateOfBirth: '1970-01-01'
},
{
id: '3',
name: 'daisy',
dateOfBirth: '2000-01-01'
},
{}
]
// Objects contain properties can be removed but empty object can not be removed.
const deleteItem = (index) => {
return array.splice(index, 1);
};
Use Array.filter to filter out the items which have no properties
let array = [
{id:"1",name:"sam",dateOfBirth:"1998-01-01"},
{id:"2",name:"chris",dateOfBirth:"1970-01-01"},
{id:"3",name:"daisy",dateOfBirth:"2000-01-01"},
{}
]
const filtered = array.filter(e => Object.keys(e).length)
console.log(filtered)
The above works since Object.keys will return an array of the properties of the object. Getting its length property will get the number of items in the array. If the length property is 0, it is coerced to false (see: Falsy values).

Delete objects from array of objects

Object {Results:Array[3]}
Results:Array[3]
[0-2]
0:Object
id=1
name: "Rick"
upper:"0.67"
1:Object
id=2
name:'david'
upper:"0.46"
2:Object
id=3
name:'ashley'
upper:null
I have this array of objects as shown above. and a variable named delete_id
delete_id = 1,2
So this indicates objects with id 1 and 2. It should delete the objects in the array of objects and give the final result as follows:
Object {Results:Array[1]}
Results:Array[3]
[0]
0:Object
id=3
name:'ashley'
upper:null
Can someone let me know how to achieve this. I tried to use this below function. It only deletes the first value in variale delete_id. i.e. id with 1 is deleted. similary if we have delete_id = 2,3 then it only deletes 2. I want to delete 2 and 3 both...
function removeID(delete_id) {
tabledata = tabledata.filter(function (obj) {
return delete_id.indexOf(obj.id);
});
You can use .split() and .map() to transform your delete_id string into an array of numeric IDs. Then, you can use .filter() to do the cleanup.
var players = [
{
id: 1,
name: "Rick",
upper: "0.67"
},{
id: 2,
name: "david",
upper: "0.46"
},{
id: 3,
name: "ashley",
upper: null
}
];
var delete_id = "1,2";
var exclude = delete_id.split(',').map(Number);
players = players.filter(function(player) {
return exclude.indexOf(player.id) == -1;
});
console.log(players);
function findObj(array,value,key) {
var result = array.filter(function (obj) {
if (obj[key] === value || obj[key] == value)
return obj;
});
return result;
};
First find the object from the
array(tabledata),value=1(delete_id),key=the key in json(id)
var selectedObj=findObj(tabledata,delete_id,'id');
get index of that object in the array
var index=tabledata.indexOf(selectedObj[0]);
delete its index
tabledata.splice(index,1);
The code runs if you change the removeID code to see if the index is equal to -1
function removeID(delete_id) {
tabledata = tabledata.filter(function(obj) {
return delete_id.indexOf(obj.id)===-1; //added === -1 here
});
}
var tabledata = [{
id: 1,
name: "Rick",
upper: "0.67"
}, {
id: 2,
name: 'david',
upper: "0.46"
}, {
id: 3,
name: 'ashley',
upper: null
}];
var ids = [1,2]; //defined it as an array (not sure if you did)
removeID(ids);
console.log(tabledata);
I assume that delete_id is an integer array. In that case you can filter to exclude provided ids with code below.
It'll check if obj.id is not in delete_id, then obj will be included in a new filtered array. Also it will leave tabledata intact.
var filtered = tabledata.filter(function(obj) {
return !(obj.id in delete_id)
})

How to pluck multiple attributes from a Backbone collection?

I am trying to pluck multiple attributes from a Backbone collection but it returns undefined.
collection
{
id:1,
name:"raju",
age:23,
sex:male,
hobbies:..
}
{
id:2,
name:"ramesh",
age:43,
sex:male,
hobbies:..
}
... //many models
I am trying to get multiple attributes from collection.
collection.pluck(["id","name","age","sex"]);
Expected output
[{//multiple attributes},{}]
is there any alternative way to get multiple attributes?
As #elclanrs said, collection.pluck extracts a single attribute, you will have to use _.map with a custom extraction function. Something like
var c = new Backbone.Collection([
{id: 1, name: "raju", age: 23, sex: "male"},
{id: 2, name: "ramesh", age: 43, sex: "male"}
]);
var plucked = c.map(function (model) {
return _.pick(model.toJSON(), ["name", "age"]);
});
console.log(plucked);
And a demo http://jsfiddle.net/U7p9u/
You could simplify this call by combining Collection.invoke and Model.pick
var c = new Backbone.Collection([
{id: 1, name: "raju", age: 23, sex: "male"},
{id: 2, name: "ramesh", age: 43, sex: "male"}
]);
plucked = c.invoke("pick", ["name", "age"]);
console.log(plucked);
http://jsfiddle.net/U7p9u/5/
In a similar spirit, if your extraction function is defined on the prototype of your models:
var M = Backbone.Model.extend({
mypluck: function () {
return this.pick("name", "age");
}
});
var C = Backbone.Collection.extend({
model: M
});
var c = new C([
{id: 1, name: "raju", age: 23, sex: "male"},
{id: 2, name: "ramesh", age: 43, sex: "male"}
]);
var plucked = c.invoke("mypluck");
console.log(plucked);
http://jsfiddle.net/U7p9u/3/
In the docs it says:
"[pluck is the] Equivalent to calling map and returning a single
attribute from the iterator."
This leads me to believe that it isn't possible with multiple properties because you're basically replacing one item in the collection with one of its properties. So basically you're doing this:
var collect = [{a:'foo',b:'baz'},{a:'lol',b:'fur'}];
var key = 'a';
var result = collect.map(function(o){ return o[key] });
A possible solution would be to return an array and then flatten it, something like this:
result = [].concat.apply([],collect.map(function(o){ return [o.a,o.b]; }));
console.log(result); //=> ["foo", "baz", "lol", "fur"]
http://jsfiddle.net/CoryDanielson/Lj3r85ew/
You could add select methods to collections and models.
(or name it whatever you feel is appropriate)
/**
Backbone Model Select/Multi-get -------------------------------------------
*/
Backbone.Model.prototype.select = function(props) {
if ( arguments.length > 1 ) {
props = slice.call(arguments);
}
if ( _.isArray(arguments[0]) ) {
props = arguments[0];
}
// If requesting multiple, return all props
if ( _.isArray(props) ) {
return _.object(props, _.map(props, _.bind(this.get, this)));
}
// Else, return single property
return this.get(props);
}
/**
Backbone Collection Select ------------------------------------------------
*/
Backbone.Collection.prototype.select = function(props) {
if ( arguments.length > 1 ) {
props = slice.call(arguments);
}
if ( _.isArray(arguments[0]) ) {
props = arguments[0];
}
return _.map(this.models, function(m) {
return m.select(props);
});
}
This would allow you to select multiple properties across all models of a collection, or select multiple properties on a model.
collection.select('id', 'first', 'last'); // or ['id', 'first', 'last']
model.select('first', 'last'); // or ['first', 'last']

Categories