I have the following code which should filter one dynamic array (up to 300 thousands elements) from all elements not contained in another constant array:
orders[] // is already filled with data
let materials = [] // create empty array
for (let scheme in schemes) { // loop constant object
materials.push(schemes[scheme].typeID) // take id and add it to materials array
}
materials = Array.from(new Set(materials)) // filter out duplicates
console.log(materials) // everything looks fine here, 83 unique ids
for (let order in orders) { // now loop the main array
if (!materials.includes(orders[order].type_id)) { // if order's containment id is not found in materials array
orders.splice(order,1) // remove it from array
order -= 1 // and one step back to compensate removed index (do I need it or is it processed normally even after .splice?)
}
}
// and send filtered orders into browser when certain url is requested
However not all unnecessaty records are filtered out, there are lots and lots of them whose id cannot be found in materials array.
What is my mistake and where is error?
for (let scheme in schemes)
Thats how you iterate over keys in an object. Rather iterate over the entries in an array:
for (let scheme of schemes)
Additionally you should consider using the Set for lookup as its much faster. And map and filter might be useful:
const materials = new Set(schemes.map(scheme => scheme.typeID));
orders = orders.filter(el => materials.has(el.type_id));
Related
I am trying to iterate over an array of array objects to de-dupe and sort the data within each. The function onlyUnique returns unique values in an array. The problem is, it doesn't work as intended.
arr_lists = [arr_1, arr_2, arr_3, arr_4, arr_5, ...]
for (var list_obj of arr_lists) {
list_obj = list_obj.join().split(',').filter(onlyUnique);
list_obj.sort();
Logger.log(list_obj);
}
The logger results show true (i.e. they are what I am looking for), but the original array is unchanged, although I think it should have been updated.
I've tried assigning the filtered array to a new array... nope.
I know that I could add a thousand lines of code to achieve the results, but that seems silly.
I suspect it's something obvious.
You can simply achieve it by using Set data structure to remove the duplicates and Array.sort() compare function to sort the elements in an array.
Live Demo :
const arr_lists = [[2,3,5,6], [7,2,5,3,3], [1,5,3], [4,7,4,7,3], [1,2,3]];
arr_lists.forEach((arr, index) => {
arr_lists[index] = [...new Set(arr)].sort((a, b) => a -b);
})
console.log(arr_lists);
const arrPassword = []
const passarrayLength = 5
function addPassword(passwd) {
if(arrPassword.length === passarrayLength)
{
arrPassword.shift()
}
arrPassword.push(passwd)
console.log(arrPassword.length)
console.log(arrPassword)
}
addPassword('Pass')
addPassword('Pass2')
addPassword('Pass3')
addPassword('Pass4')
addPassword('Pass5')
addPassword('Pass6')
addPassword('Pass7')
addPassword('Pass8')
addPassword('Pass9')
addPassword('Pass10')
I have a few cases where I want to store objects like user password history in an Array of objects to ensure he has not used the password in the last 5 times for example. My question is can I specify an array of objects with a size of 5 and then just push new passwords to array and any object in the array above size set would be discarded ? Or do I have to do this my self where I count the objects in my Array and if it is = max size I pop the oldest one before I push the new object to array ?
Based on the research I did typescript or javascript does not have a fixed array size, I can specify a array of 3 5 objects but will need to assign all 5 and even so the push would make it 6 objects as there is no limit.
So what would be the best approach to handle this ?
I included some basic concept i cam up with
Can I specify an array of objects with a size of 5 and then just push new passwords to array and any object in the array above size set would be discarded?
Nope. Arrays in javascript do not have a maximum size, so there is no "built in" way to do this.
Or do I have to do this my self where I count the objects in my Array and if it is = max size I pop the oldest one before I push the new object to array?
Yep, that's exactly right. It shouldn't be too hard to make a little class that handles this logic.
When i need a functionality and there happens to be no such a functionality, the first thing that i think is "what am i missing?".
In this particular case all you need to do is to take the last passarrayLength many items from your arrPassword array and reassign it to the arrPassword array like;
arrPassword = arrPassword.slice(-passarrayLength);
like
[1,2,3].slice(-5); // <- [1,2,3]
[1,2,3,4,5,6,7,8,9].slice(-5); // <- [5,6,7,8,9]
I have a javascript array of nested data that holds data which will be displayed to the user.
The user would like to be able to apply 0 to n filter conditions to the data they are looking at.
In order to meet this goal, I need to first find elements that match the 0 to n filter conditions, then perform some data manipulation on those entries. An obvious way of solving this is to have several filter statements back to back (with a conditional check inside them to see if the filter needs to be applied) and then a map function at the end like this:
var firstFilterList = _.filter(myData, firstFilterFunction);
var secondFilterList = _.filter(firstFilterList, secondFilterFunction);
var thirdFilterList = _.filter(secondFilterList, thirdFilterFunction);
var finalList = _.map(thirdFilterList, postFilterFunction);
In this case however, the javascript array would be traversed 4 times. A way to get around this would be to have a single filter that checks all 3 (or 0 to n) conditions before determining if there is a match, and then, inside the filter at the end of the function, doing the data manipulation, however this seems a bit hacky and makes the "filter" responsible for more than one thing, which is not ideal. The upside would be that the javascript Array is traversed only once.
Is there a "best practices" way of doing what I am trying to accomplish?
EDIT: I am also interested in hearing if it is considered bad practice to perform data manipulation (adding fields to javascript objects etc...) within a filter function.
You could collect all filter functions in an array and check every filter with the actual data set and filter by the result. Then take your mapping function to get the wanted result.
var data = [ /* ... */ ],
filterFn1 = () => Math.round(Math.random()),
filterFn2 = (age) => age > 35,
filterFn3 = year => year === 1955,
fns = [filterFn1, filterFn2, filterFn2],
whatever = ... // final function for mapping
result = data
.filter(x => fns.every(f => f(x)))
.map(whatever);
One thing you can do is to combine all those filter functions into one single function, with reduce, then call filter with the combined function.
var combined = [firstFilterFunction, seconfFilterFunction, ...]
.reduce((x, y) => (z => x(z) && y(z)));
var filtered = myData.filter(combined);
I missing something when trying to push to an array while preventing duplicates.
I keep figuring out code that will push every occurence of an employee to the new employees array but I cannot figure out how to only push an unique list.
My final array is a 2d array so that can be setValues() back into a column in the Google sheet.
function queryEmployees(){
var sh = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
var lRow = sh.getLastRow();
var data = sh.getRange(1,1,lRow,2).getValues();
var employees = [];
for(i=0;i<data.length;i++){
if(data[i][0]==='Team member evaluated'){
if(employees.indexOf([data[i][1]])===-1){
employees.push([data[i][1]]);
}
}
}
Logger.log(employees);
Logger.log(employees.length);
SpreadsheetApp.getActiveSpreadsheet().getSheets()[1]
.getRange(1,1,employees.length,1).setValues(employees);
}
IndexOf does not work with objects in arrays without your rewriting the function or writing your own. It works fine with strings, though. So a simple fix is to create a parallel array of strings, which allows us to keep your code almost intact. Thus, add,
var employeesIndex=[];
after your
var employees=[]
change the condition on your inner "if" clause to
(employeesIndex.indexOf(data[i][1])===-1)
and within that if block add a line to update the index
employeesIndex.push(data[i][1]);
That way the index tracks duplicates for you while your employees array contains arrays like you need.
I have two javascript JSON arrays as follows:
this.BicyclePartsOLD;
this.BicyclePartsNEW;
So basically both have an attribute "ListOrder". The OLD is ordered by ListOrder from 1 to n items.
The NEW one is modified but had the same records as BicyclePartsOLD, so OLD needs to get updated from NEW. If someone changed ListOrder from 1 to 3 in NEW I need to update the OLD list to have that value to 3 and make ListOrder 2 = 1, ListOrder 3 = 2.
I am trying to do it the following way but I am stuck on the best way to set the ListOrder to the new numbers:
for(var i = 0; i < this.BicyclePartsOLD.length; i++)
{
for(var j = 0; j < this.BicyclePartsNEW.length; j++)
{
if(this.BicyclePartsOLD[i].PartNumber === this.BicyclePartsNEW[j].PartNumber)
{
this.BicyclePartsOLD[i].ListOrder = this.BicyclePartsNEW[j].ListOrder;
//NOT Sure how to reorder BicyclePartsOLD here, there will be another
//item with the same ListOrder at this point.
}
}
}
Any advices that would lead me into the correct direction would be much appreciated.
Thinking out of the box, instead of having 2 arrays with the same data but totally unrelated in terms of objects, why not create 2 arrays, both containing the same objects? That way, editing an object makes it look like you're editing it in both places.
First of all, you can have 2 arrays but both point to the same objects:
Array1 -> [{foo:'bar'},{baz:'bam'}]
Array2 -> [{baz:'bam'},{foo:'bar'}]
The object with the foo in the first array can be the same exact object with the foo on the other array (I mean the same object instance, not just because they have the same properties). So editing one will basically look as if they changed in both places.
So with that concept, you can just do a slice() on the NEW array to give you a 1-level copy of the array. Basically, it's the same exact items in a different array container. You can then sort the newly sliced array however you want it.
this.BicyclePartsOLD = this.BicyclePartsNEW.slice().sort(function(){...});
Now to avoid repeatedly slicing like my first solution, I suggest you create both OLD and NEW arrays first. Then when you add an entry, create an object with your data and push that object into both arrays, that way both arrays hold the same object, and editing it will reflect on both arrays.
Something like this:
var OLD = [];
var NEW = [];
// Adding an entry
var newItem = {}
OLD.push(newItem);
NEW.push(newItem);
//Editing that item should reflect on both arrays, since they're the same
OLD[0].someProperty = 'someValue';
console.log(OLD[0].someProperty); // someValue
console.log(NEW[0].someProperty); // someValue
// An item only on OLD
var oldItem = {};
OLD.push(oldItem);
// An item only on OLD
var yetAnotherOldItem = {};
OLD.push(yetAnotherOldItem);
// Let's bring one of those old items to NEW and edit it
NEW.push(OLD[2]);
OLD[2].revived = 'I feel new!';
// Should be in both arrays, but in different indices (since there's the second OLD item)
console.log(OLD[2].revived); // someValue
console.log(NEW[1].revived); // someValue