How to lessen this comparing loop - javascript

I need to find which id numbers are missing inside s.data compared to users.
Is there a better(smaller code) way to compare?
Thanks ;)
if(users.length != undefined)
{
for(y=0;y<users.length;y++)
{
var left = true;
for(y2=0;y2<s.data.length;y2++)
{
if(users[y].client_id==s.data[y2].client_id) {left = false;break;}
}
if(left) {users[y].ref.remove();delete users[y];}
}
}
else if(!jQuery.isEmptyObject(users))
{
var left = true;
for(y2=0;y2<s.data.length;y2++)
{
if(users.client_id==s.data[y2].client_id) {left = false;break;}
}
if(left) {users.ref.remove();users = {};}
}
Haven't checked if this is working code. :)

First, off, the 2nd branch appears to be nothing but a specialization of the first branch. You can use this to either make the "2nd" users = [users] (in which case users really means users and not a-user) and eliminates the top branch entirely, or remove the the logic into a function invoked per-user.
Now, to tackle the inner loop: What this is a 'map' and a 'contains'. Looking at it just in terms of a contains:
// Returns true if any item in data.client_id (an array)
// is that of user.client_id
function dataContains (user, data) {
for (var i = 0; i < data.length; i++) {
if (data[i].client_id == user.client_id) {
return true
}
}
return false
}
Now the code is reduced to:
for (each user) {
if (!dataContains(user, data)) {
// do something here
}
}
However, we could go one step further and use a generic 'contains' if we also have a 'map'. The final form is then:
var dataIds = map(data, function (x) { return x.client_id })
for (each user) {
if (!contains(user.client_id, dataIds)) {
..
}
}
Where the 'contains' is much more generalized:
// Returns true iff item is contained within arr
function contains (item, arr) {
// Just do what the comment documentation says
}
If you are using jQuery you already have handy functions:
'contains' - inArray, and a "sorta" 'map' - map. However, be warned! The jQuery 'map' is really a flat-map and was given an incorrect name and incomplete documentation!
I believe ECMAScript ED5 has these functions standard.
Also, you could invert the client_id's in the data to object keys and simply test for key existence, which is O(1) vs. O(n) iff the look-up is built once (or at least much, much less than it's used) and so it may be "theoretically" better. The size of n makes a large difference if it will actually matter, if at all. In this case it's likely the look-up could be built incrementally and saved between times this code is executed.
var existingIds = {}
for (var i = 0; i < data.length; i++) {
existingIds[data[i].client_id] = true
}
for (each user) {
if (!existingIds[user.client_id]) {
..
}
}

Related

How do i push an array[i] to another array

Basically i have to create a quiz with 3category. each with 5questions.
I would have to push the selected category-questions into this new array from the array with all the questions. I am unable to do so.
pushSelectedQuestion() {
for (var i = 0; i < this.getNumberOfQuestion; i++) {
if (usercategory == questionPool[i].category) {
mcqSelected.push(questionPool[i])
return mcqSelected;
}
}
}
usercategory = input from user.
if user chooses category 1.
if (1 == questionPool[1].category) (if it matches the category) then it will be pushed.
This is the part which i cant do
Well, from the information you've provided, there's one main issue here - the return statement is definitely shortcutting the loop - so even if you have everything else right, you'll only ever get the first matching question. The rest will have been cut out by the return statement, which stops the function and returns the value.
pushSelectedQuestion() {
for (var i = 0; i < this.getNumberOfQuestion; i++) {
if (usercategory == questionPool[i].category) {
mcqSelected.push(questionPool[i])
// the below line is causing this loop to end after the first time through the list.
// Remove it and then put a console.log(mcqSelected);
// here instead to see the value during each iteration of the loop.
return mcqSelected;
}
}
}
There are a lot of ways to accomplish what you want to do here though. For example, you could just use the javascript Array.filter method like so
let selectedQuestions = questionPool.filter(question => question.category == userCategory)
Maybe I am not understanding your question correctly, but can't you use nested arrays. If the questions are categorized beforehand that is.

Javascript observer or proxy without all changes going through proxy

I'm writing a subclass of arrays in Javascript to have better support for matrix operations (I know others exist, this is partially for me to re-teach myself linear algebra), and what I want is to have some properties that are reset whenever any values in the matrix are adjusted. Some calculations like the determinant are computationally intensive, and I'd like to be able to store them to avoid re-calculation, but then they need to be reset to null whenever any matrix elements are changed.
Essentially, it seems like what i want is the deprecated Array.observe(). And the replacement, proxies, seem like a lot of overhead for this one thing. As alluded to in some of the comments on Detecting Changes in a Javascript Array using the proxy object that were not directly addressed, I don't want to have to access my matrices only ever through proxies. I use a lot of handy [i][j] indexing and [mat[i], mat[j]] = [mat[j], mat[i]] in the code I've written so far.
class Matrix extends Array {
constructor() {
var args = [];
for (var i = 0; i < arguments.length; i++) {
if (Array.isArray(arguments[i])) {
args.push(new Matrix(...arguments[i]));
} else {
args.push(arguments[i]);
}
}
super(...args);
this._determinant = null;
}
determ(forceRecalculate = false) {
if (this._determinant === null || forceRecalculate) {
this.upperEchelon();
}
return this._determinant;
}
upperEchelon(reduced = false) {
//There's a lot of code here but in the process of doing this other thing
//you get 99% of the way to calculating the determinant so it does this
this._determinant = factor;
}
}
Basically, I want anything like mat[0][0] = 10 or mat.push([2,4,5]) that updates the values in the matrix to set mat._determinant = null. Or any equivalent method of flagging that it needs to be re-calculated next time it's asked for. I'm not opposed to using proxies necessarily if someone can help me figure out the implementation, I would just rather have this set-to-null-on-update property be inherent to my class functionality.
What I really want is a way to overload base methods like [] a la C# so the functions that do the updating would trigger this without changing syntax, but I've resigned myself to not having that in JS.
While a Proxy would work, it would also be pretty slow. A different approach would be for every method that needs to use the value of _determinant go through a different function first to check to see if the _determinant needs to be updated (and if so, updates it). This way, the expensive recalculation is not done every time the array changes, but only just in time for the result to be used. For example:
class Matrix extends Array {
constructor() {
var args = [];
for (var i = 0; i < arguments.length; i++) {
if (Array.isArray(arguments[i])) {
args.push(new Matrix(...arguments[i]));
} else {
args.push(arguments[i]);
}
}
super(...args);
this._determinant = null;
}
// next method is effectively a recursive deep join
// could also use toString if it doesn't interfere with anything else
getString() {
const itemsStr = this.map((item) => (
item instanceof Matrix
? item.getString()
: item
))
.join(',');
const result = '[' + itemsStr + ']';
return result;
}
getDeterm() {
const newString = this.getString();
if (newString !== this._lastString) {
this._lastString = newString;
this.upperEchelon();
}
return this._determinant;
}
upperEchelon() {
console.log('running upperEchelon');
this._determinant = Math.random();
}
}
const m = new Matrix([2, 3, 4], 5);
console.log(m.getDeterm());
// Not calculated again:
console.log(m.getDeterm());
// Mutation, next call of getDeterm will run upperEchelon:
m[0][0] = 1;
console.log(m.getDeterm());

recursion on returning vectors c++

Hey guys I am trying trying to right this javascript code into c++. I am doing quick sort and everything is straight forward minus the last step.
function quickSort(arr)
{
//base case if the arr is 1 or 0 then return the array
if(arr.length === 1 || arr.length === 0)
{
return arr;
}
var pivotIndex = Math.floor(arr.length/2);
var pivotValue = arr[pivotIndex];
var before = [];
var after = [];
for(var counter = 0; counter < arr.length; counter++)
{
if(counter === pivotIndex)
continue;
if(pivotValue <= arr[counter])
{
before.push(arr[counter])
}
else
{
after.push(arr[counter])
}
}
//this step I am having trouble rewriting in c++
return quickSort(after).concat(pivotValue).concat(quickSort(before));
}
I am having a hard time rewriting the recursive step in c++. I am not sure how concat 2 vector. I tried using the insert method but I keep getting an error about invalid use of void expression.
vector<int> quickSort(vector<int> arr)
{
if(arr.size() == 1 || arr.size() == 0)
{
return arr;
}
int pivotIndex = arr.size()/2;
int pivotValue = arr[pivotIndex];
vector<int> before;
vector<int> after;
//put values in before or after the piv
for(size_t counter = 0; counter < arr.size(); counter++)
{
if(counter == pivotIndex)
continue;
if(pivotValue <= arr[counter])
before.push_back( arr[counter]);
else
after.push_back( arr[counter]);
}
return //????? not sure how to do this
}
So, you realized that your core question was "how to concatenate two vectors", and you found a right answer: using insert. Now your question is about why you were getting "an error about invalid use of void expression." (That's the assumption my answer is for, at least.)
That's because you were likely trying to do something like the following:
return quickSort(after).insert( /* stuff */ );
which is wrong. In JavaScript, array.concat returns the concatenated array. It's return type is effectively Array, and so doing return arr.concat(arr2) returns an Array because arr.concat would return an Array. Further, in JavaScript, array.concat doesn't modify the array it was called on, but rather returns a new array.
In C++, however, vector.insert (#4 in the reference) returns void. That means it returns nothing. So when you try to return the result of insert, you get that error about invalid use of a void expression. Further, in C++, vector.insert does modify the vector it was called on.
So how do you use insert in this case?
vector<int> quickSort(vector<int> arr)
{
// ...
// Sort `before` and `after`
before = quickSort(before);
after = quickSort(after);
// Modify `after` and return it.
after.push_back(pivotValue);
after.insert(after.end(), before.begin(), before.end());
return after;
}
Note: My code isn't optimal and the idea of rewriting JS in C++ is also oddly specific. My answer is to simply outline the problem asked in the question, not to give a good C++ implementation of quick sort.
To concat two vector , you can use std::merge
like:std::merge(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(dst));

How can I remove an object from an array if I know the value of one field of the object?

I tried to find out some good examples but SO seems to have mainly examples from 4-5 years ago and I would like to use a solution that would work using modern browser capabilities.
Ihave an array of test objects:
var tests;
Each test object contains a testId.
How can I remove test object with testId = 25 from the array tests. I was thinking of a for loop but is there a cleaner way to do this?
The best answer depends on whether you know in advance whether there's at most one match, or potentially more than one (and in the latter case whether you want to remove all of them or just the first)
Removing all matches
The "simplest" way is to use filter, although strictly that produces a new array without the matching element:
tests = tests.filter(function(e) {
return e.testId !== 25;
});
This is OK, unless other code is holding a reference to the original array.
Modifying the array safely "in-place" still appears to require a combination of a for loop with .splice:
for (var i = 0; i < tests.length; ) { // nb: deliberate .length test
if (tests[i].testId === 25) {
tests.splice(i, 1);
} else {
++i;
}
}
The "safely" caveat is because the functional methods of iterating through an entire array will get confused if the current element in the array is removed. That is not a concern in the "first match" methods shown below.
Removing first (or only) match
The plain for method is still pretty simple (and probably most efficient, too!)
for (var i = 0, n = tests.length; i < n; ++i) {
if (tests[i].testId === 25) {
tests.splice(i, 1);
break;
}
}
The .some method per Johan's answer can iterate through an array and then exit on first match (although some may object on philosophical grounds to a boolean predicate function also mutating the array):
var didRemove = tests.some(function(e, i, a) {
if (e.testId === 25) {
a.splice(i, 1);
return true; // causes the loop to exit
}
});
In ES6-draft there's .findIndex, which is a generalisation of .indexOf:
var index = tests.findIndex(function(e) {
return e.testId === 25;
});
if (index >= 0) {
tests.splice(index, 1);
}
One way is to loop through all objects and splice a matching object out of the array.
Instead of forEach I use some (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some). Because with the some method you can "break" the loop by returning true so that you don't need to go through all objects if a match has been found.
tests.some(function(testObject, index) {
if (testObject.testId === 25) {
tests.splice(index, 1);
return true;
}
});
Or wrap it in a function
var removeObjectById = function(id) {
tests.some(function(testObject, index) {
if (testObject.testId === id) {
tests.splice(index, 1);
return true;
}
});
}
removeObjectById(25)

Javascript 'First or Default' function for 'associative arrays'/objects

Is there a better way to do this?
I'm storing values in what some would erroneously call an associated array:
The tokens object stores.... tokens and a count of documents using that token on a per-db level.
var tokens = {'db1' : { '654321': { 'docCount': 1 },
'321456': { 'docCount': 2 } },
'db2' : { '999999': { 'docCount': 1 } } };
I can add/remove dbs and tokens and update the docCounts appropriately.
We can assume, due to code omitted for brevity, that if a db exists, a token also exists with a docCount of at least 1.
If a db exists and I need to retrieve ANY of its tokens, what is the best method?
If the dbs held arrays, it would be as easy as tokens['db1'][0]... but I'm not using arrays.
I have something like the following, "inspired" by LINQ (please don't blame LINQ):
// NOTE: default not implemented here
var firstOrDefault = function(obj) {
var thing;
for (var i in obj) {
thing = i;
break;
}
return thing;
};
which would be called as so (simplified for example):
var anyToken;
if (tokens['db1') { anyToken = firstOrDefault(tokens['db1']); }
Generally returning per the above example '654321' (as this is an object, not an array, order is not guaranteed, but either value is acceptable in my code).
Is this a reasonable method to get any value?
Is there a better method?
Should I just suck it up, shove everything into an array, and wrap the storage features that way?
UPDATE: I've removed the default reference, as an unfound item will a perfectly acceptable undefined response:
// NOTE: obj.hasOwnProperty not implemented for brevity
var firstOrAny = function(obj) {
var thing;
for (var i in obj) {
thing = i;
break;
}
return thing;
};
which would be called as so (simplified for example):
var anyToken;
if (tokens['db1') { anyToken = firstOrAny(tokens['db1']); }
Slightly shorter solution:
var firstOrDefault = function(obj, d) {
for (var i in obj)
{
if (obj.hasOwnProperty(i))
{
return obj[i];
}
}
return d;
};
But yes, it is the fastest way to get any (usually first inserted) key from an object.
I also added a hasOwnProperty check to prevent cases where the values are retrieved from the prototype chain.

Categories