Delete objects from array of objects - javascript

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)
})

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);

Getting value through DOM and then filter an array for the value returns undefined

I have written a function which is supposed to filter through an array and return a value associated with the given value. For example, by knowing a name, I want to get the initials.
array
let members = [
{
id: 1,
memberFullName: "Ben Stiller",
memberInitials: "BS"
},
{
id: 2,
memberFullName: "Michael Jackson",
memberInitials: "MJ"
}
];
function
function findMemberInitials(object) {
let result = members.filter( obj => {
return obj.memberFullName == object;
})[0].memberInitials;
}
When I run the array like findMemberInitials("Ben Stiller"); it returns BS as expected.
When I try to get the value from at user input first and then run it through the function, it returns undefined.
let getMemberName = document.getElementById("name").value;
let getMemberInitials = findMemberInitials(getMemberName);
console.log(getMemberInitials); //returns undefined.
I'm not quite sure what I am doing wrong. I've tried parsing it to a string, but it didn't help.
You are not returning anything from function. Secondly you should use find()
let members = [
{
id: 1,
memberFullName: "Ben Stiller",
memberInitials: "BS"
},
{
id: 2,
memberFullName: "Michael Jackson",
memberInitials: "MJ"
}
];
function findMemberInitials(object) {
return (members.find(obj => obj.memberFullName === object) || {}).memberInitials;
}
console.log(findMemberInitials("Michael Jackson"))

Merge objects with corresponding key values from two different arrays of objects

I've got two arrays that have multiple objects
[
{
"name":"paul",
"employee_id":"8"
}
]
[
{
"years_at_school": 6,
"department":"Mathematics",
"e_id":"8"
}
]
How can I achieve the following with either ES6 or Lodash?
[
{
"name":"paul",
"employee_id":"8"
"data": {
"years_at_school": 6
"department":"Mathematics",
"e_id":"8"
}
}
]
I can merge but I'm not sure how to create a new child object and merge that in.
Code I've tried:
school_data = _.map(array1, function(obj) {
return _.merge(obj, _.find(array2, {employee_id: obj.e_id}))
})
This merges to a top level array like so (which is not what I want):
{
"name":"paul",
"employee_id":"8"
"years_at_school": 6
"department":"Mathematics",
"e_id":"8"
}
The connector between these two is "employee_id" and "e_id".
It's imperative that it's taken into account that they could be 1000 objects in each array, and that the only way to match these objects up is by "employee_id" and "e_id".
In order to match up employee_id and e_id you should iterate through the first array and create an object keyed to employee_id. Then you can iterate though the second array and add the data to the particular id in question. Here's an example with an extra item added to each array:
let arr1 = [
{
"name":"mark",
"employee_id":"6"
},
{
"name":"paul",
"employee_id":"8"
}
]
let arr2 = [
{
"years_at_school": 6,
"department":"Mathematics",
"e_id":"8"
},
{
"years_at_school": 12,
"department":"Arr",
"e_id":"6"
}
]
// empObj will be keyed to item.employee_id
let empObj = arr1.reduce((obj, item) => {
obj[item.employee_id] = item
return obj
}, {})
// now lookup up id and add data for each object in arr2
arr2.forEach(item=>
empObj[item.e_id].data = item
)
// The values of the object will be an array of your data
let merged = Object.values(empObj)
console.log(merged)
If you perform two nested O(n) loops (map+find), you'll end up with O(n^2) performance. A typical alternative is to create intermediate indexed structures so the whole thing is O(n). A functional approach with lodash:
const _ = require('lodash');
const dataByEmployeeId = _(array2).keyBy('e_id');
const result = array1.map(o => ({...o, data: dataByEmployeeId.get(o.employee_id)}));
Hope this help you:
var mainData = [{
name: "paul",
employee_id: "8"
}];
var secondaryData = [{
years_at_school: 6,
department: "Mathematics",
e_id: "8"
}];
var finalData = mainData.map(function(person, index) {
person.data = secondaryData[index];
return person;
});
Sorry, I've also fixed a missing coma in the second object and changed some other stuff.
With latest Ecmascript versions:
const mainData = [{
name: "paul",
employee_id: "8"
}];
const secondaryData = [{
years_at_school: 6,
department: "Mathematics",
e_id: "8"
}];
// Be careful with spread operator over objects.. it lacks of browser support yet! ..but works fine on latest Chrome version for example (69.0)
const finalData = mainData.map((person, index) => ({ ...person, data: secondaryData[index] }));
Your question suggests that both arrays will always have the same size. It also suggests that you want to put the contents of array2 within the field data of the elements with the same index in array1. If those assumptions are correct, then:
// Array that will receive the extra data
const teachers = [
{ name: "Paul", employee_id: 8 },
{ name: "Mariah", employee_id: 10 }
];
// Array with the additional data
const extraData = [
{ years_at_school: 6, department: "Mathematics", e_id: 8 },
{ years_at_school: 8, department: "Biology", e_id: 10 },
];
// Array.map will iterate through all indices, and gives both the
const merged = teachers.map((teacher, index) => Object.assign({ data: extraData[index] }, teacher));
However, if you want the data to be added to the employee with an "id" matching in both arrays, you need to do the following:
// Create a function to obtain the employee from an ID
const findEmployee = id => extraData.filter(entry => entry.e_id == id);
merged = teachers.map(teacher => {
const employeeData = findEmployee(teacher.employee_id);
if (employeeData.length === 0) {
// Employee not found
throw new Error("Data inconsistency");
}
if (employeeData.length > 1) {
// More than one employee found
throw new Error("Data inconsistency");
}
return Object.assign({ data: employeeData[0] }, teacher);
});
A slightly different approach just using vanilla js map with a loop to match the employee ids and add the data from the second array to the matching object from the first array. My guess is that the answer from #MarkMeyer is probably faster.
const arr1 = [{ "name": "paul", "employee_id": "8" }];
const arr2 = [{ "years_at_school": 6, "department": "Mathematics", "e_id": "8" }];
const results = arr1.map((obj1) => {
for (const obj2 of arr2) {
if (obj2.e_id === obj1.employee_id) {
obj1.data = obj2;
break;
}
}
return obj1;
});
console.log(results);

Javascript - how to get just the value of the property after filtering and mapping the array of objects

I am filtering and mapping the array objects that looks like this:
taxonomy:Object
data:Array[2]
0:Object
id:377
name:"Buss"
slug:"buss"
type:"post_tag"
1:Object
My function looks like this:
let tag = this.article.taxonomy.data.filter(function( data ) {
return data.type.includes('tag')
}).map(function(obj) {
return obj.name;
});
return tag;
What I am just wondering is there a way to get from the map function just the string name value, since now it returns ["Buss"], so that don't need to use the index at the end of the function:
return tag[0]
It sounds like you want find, not filter, if you're looking only for one result. find returns the first entry for which the callback returns a truthy value, or undefined if it never does. So:
const obj = this.article.taxonomy.data.find(data => data.type.includes('tag'));
const tag = obj && obj.name; // Note the guard in case no entry matched
return tag; // Will be the name or `undefined`
(Note that I've assumed you can use an arrow function, as you're using let. If not, just replace it with a function function.)
Live Example:
const taxonomy = {
data: [
{
id: 375,
name: "A",
slug: "A",
type: "nope"
},
{
id: 376,
name: "B",
slug: "B",
type: "nor-this"
},
{
id: 377,
name: "Buss",
slug: "buss",
type: "post_tag"
},
{
id: 378,
name: "C",
slug: "C",
type: "blah"
}
]
};
const obj = taxonomy.data.find(data => data.type.includes('tag'));
const tag = obj && obj.name;
console.log(tag);

I have two arrays, how do I find matchings elements and perform some action? (lodash)

var array1 = [{Age: 24, Name: "Test", StudentID: 101, Checked: false}, {Age:25, Name: "Test", StudentID: 102, Checked: false}];
var array2 = [{ID: 101}];
If any element in array1 has a property of StudentID that is equal to an ID property present in array2 I'd like to set the Checked property in array1 to true.
Any tips? I'd like to do this without writing nested _.each statements.
This is my first take; however, I believe _.some performs an interation anyway.
_.each($scope.array1, function(element1) {
if(_.some($scope.array2, { ID: element1.ID })) {
element1.Checked = true;
}
});
You''ll have to use two loops, since you have two arrays of random length. But you don't have to nest them. Create a map from the array of IDs and then check the index.
var availableIDs = array2.map(function ( item ) { return item.ID; });
array1.forEach(function ( item ) {
if (availableIDs.indexOf(item.StudentID) !== -1) item.Checked = true;
});
Using lodash, use a sequence in which you create a map of items in array1, using _.indexBy(). Create an array of ids from array2 using _.pluck(), and use them with _.at() to get the selected items. Iterate the returned objects using _.forEach() to set the Checked property to true, and .commit() to apply the changes:
function checkById(items, selected) {
_(items) // start chained sequence
.indexBy('StudentID') // create a map of student objects by ids
.at(_.pluck(selected, 'ID')) // create an array of IDs from the objects in the selected array
.forEach(function(item) { // change the items Checked to true
item.Checked = true;
})
.commit(); // executes the chained sequence
}
var array1 = [{
Age: 24,
Name: "Test1",
StudentID: 101,
Checked: false
}, {
Age: 25,
Name: "Test2",
StudentID: 102,
Checked: false
}, {
Age: 22,
Name: "Test3",
StudentID: 103,
Checked: false
}, {
Age: 28,
Name: "Test4",
StudentID: 104,
Checked: false
}];
var array2 = [{
ID: 101
}, {
ID: 104
}];
checkById(array1, array2);
console.table(array1);
document.getElementById('demo').innerText = JSON.stringify(array1, null, ' ');
<script src="https://cdn.jsdelivr.net/lodash/3.10.1/lodash.min.js"></script>
<pre id="demo"></pre>
using a simple mapping function you can compose an easy search through all objects
var array1 = [{Age: 24, Name: "Test", StudentID: 101, Checked: false}, {Age:25, Name: "Test", StudentID: 102, Checked: false}];
var array2 = [{ID: 101}];
function search(studentList,searchQuery) {
var results = [];
studentList.forEach(function(student,sIndex) {
searchQuery.forEach(function(search,qIndex) {
if(search.ID == student.StudentID) {
results.push(student);
}
});
})
return results;
}
search(array1,array2);
what the forEach function does is iterate over each element, passing along the object of the index it's iterating, and the index that object is at.
By having a double nested map it's easy to iterate over the objects and then compare them according to the rules you define.
Then by using a scoped variable you can push matching values into that array, giving you a nice, neat clean result to return.
Now please mind, this is not the most efficient way to handle this. You could do a test which arary is longest and have that one iterate the least time.
So if there are more students than search parameters iterate the students once. If there are more search parameters than students, iterate the search paramateters once.
also you could chooose to 'prefilter" the arrays by sorting them on the index you wish to sort on, skip the ones you don't need by simple min/max exclusion and such.
But you'd be better off using a database query for searching with large quantities of data.
But if you only have a dataset of about a 1000 or so this will suffice.
Try this snippet:
_.each(array1, function (el) {
el.Checked = !!(JSON.stringify(array2).indexOf(el.StudentID) + 1) || el.Checked;
});
Or, you can do without lo-dash.js(with pure JavaScript)
var array1 = [{Age: 24, Name: "Test", StudentID: 101, Checked: false}, {Age:25, Name: "Test", StudentID: 102, Checked: false}];
var array2 = [{ID: 101}];
var students = array1.filter(function(data){
var isTrue = !!(JSON.stringify(array2).indexOf(data.StudentID)+1);
data.Checked = isTrue || data.Checked;
return isTrue;
})
console.log(students)

Categories