Find difference in two arrays - javascript

I have two arrays of email addresses and I am trying to find the difference in the two. One of the arrays contains current email address. The other contains current group members email address. I am updating the group list with the current email addresses and removing the address in the group that are not in the current email addresses. I cannot wrap my head around how I get my for loop to accomplish this. Here is my code so far...
for(i = 0; i < GROUP_USERS.length; i++){
var currentMember = GROUP_USERS[i];
for(x = 0; x < DOMAIN_USERS.length; x++){
if(DOMAIN_USERS[x] != currentMember){
continue;
} else {
}
}
It seems like I need to test the end of my loop, or something.
EDIT
I am using Google Apps Script (SDK). I will have to push all of the emails that need to be deleted to an array and then use the GroupApps class to remove those emails from the group. Then I will need to push the DOMAIN_USERS email address that do not already reside in the group, to the group. So, essentially, I will have two arrays. One array of emails that need to be removed from the group and one array of emails that need to be added to the group. Hopefully, that makes more sense.

You need create another variable to check currentMember exists in DOMAIN_USERS array
after that you can remove it from GROUP_USERS array
for (i = 0; i < GROUP_USERS.length; i++) {
var currentMember = GROUP_USERS[i];
var isContain = false;
for (x = 0; x < DOMAIN_USERS.length; x++) {
if (DOMAIN_USERS[x] == currentMember) {
isContain = true;
}
}
if (!isContain) {
emailTobeRemove.pop(currentMember);
i--;
}
}

Unless I'm misunderstanding the logic the same result can be reached with
GROUP_USERS = DOMAIN_USERS;

If I understand correctly you want to remove all emailaddresses from GROUP_USERS that aren't in DOMAIN_USERS, then add the emailaddresses from DOMAIN_USERS that aren't in GROUP_USERS to the GROUP_USERS array, correct?
You could first make a 'contains' function (for compatability you could use this instead of indexOf()):
function contains(arr, val) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] === val) {
return true;
}
}
return false;
}
Then to delete all emailaddresses from GROUP_USERS that aren't in DOMAIN_USERS. in a for loop:
for(i=0;i < GROUP_USERS.length; i++) {
if(!contains(DOMAIN_USERS, GROUP_USERS[i])) {
GROUP_USERS.splice(i, 1);
}
}
Then another for-loop to add the ones from DOMAIN_USERS to GROUP_USERS:
for(i=0; i < DOMAIN_USERS.length; i++) {
if(!contains(GROUP_USERS, DOMAIN_USERS[i])) {
GROUP_USERS.push(DOMAIN_USERS[i]);
}
}

if you are looking for difference in two arrays
use grip and inarray
demo

The 2 lists you need are the relative complement of GROUP_USERS in DOMAIN_USERS and of DOMAIN_USERS in GROUP_USERS. So define a function that finds all the members of an array a that are not in a second array b, and then use that to find which emails need to be added and deleted.
function relComp(a, b) {
var r = [];
for (var i = 0; i < a.length; i++) {
if (b.indexOf(a[i]) == -1) {
r.push(a[i]);
}
}
return r;
}
var toDelete = relComp(GROUP_USERS, DOMAIN_USERS);
var toAdd = relComp(DOMAIN_USERS, GROUP_USERS);
relComp can also be written with a filter:
function relComp(a, b) {
return a.filter(function(item) {
return b.indexOf(item) == -1;
});
}
JSFiddle

Its very easy using open source project jinqJs
See Fiddle Example
//Use jsJinq.com open source library
var current = ["a#yahoo.com", "b#yahoo.com", "c#yahoo.com", "d#yahoo.com"];
var group = ["a#yahoo.com", "d#yahoo.com", "yyy#yahoo.com", "xxx#yahoo.com"];
var currentComplex = [{email:"a#yahoo.com"},{email: "b#yahoo.com"}, {email:"c#yahoo.com"}, {email:"d#yahoo.com"}];
//Gets emails that are in current not in group
var result = jinqJs().from(current).not().in(group).select();
var result2 = jinqJs().from(currentComplex).not().in(group, 'email').select();

Related

javascript get only array elements equal to variable

I'm trying to compare the variable determineHour against the array stationRentalsHours, whenever the variable would be equal to a stationRentalsHours element, I'd like to add that element to another Array (stationRentalsHoursTemp), but only the values that match. I tried with simple operators, but that doesn't put anything into the temp array. I also tried using JQuery $.inArray, but that gives me some strange results, Equal to those in the original array. Are there any other methods of comparing a variable with an array for this particular task?
Thank you for any help.
function updateChart() {
if(canvas3){canvas3.destroy();}
var determineHour = selectNumber.options[selectNumber.selectedIndex].innerHTML;
for (var i = 0; i < stationRentalsHours.length; i++) {
/*if(determineHour == stationRentalsHours){
stationRentalsHoursTemp.push(stationRentalsHours[i]);*/
if( $.inArray(determineHour, stationRentalsHours[i])){
stationRentalsHoursTemp.push(stationRentalsHours[i]);
}
}
In this case, instead of using $.inArray, you can simply use the for loop and the index to test the equality. I guess you mixed up two things:
var determineHour = selectNumber.options[selectNumber.selectedIndex].innerHTML;
for (var i = 0; i < stationRentalsHours.length; i++) {
if( determineHour == stationRentalsHours[i]){
stationRentalsHoursTemp.push(stationRentalsHours[i]);
}
}
Better yet, use filter:
var determineHour = selectNumber.options[selectNumber.selectedIndex].innerHTML;
stationRentalsHoursTemp = stationRentalsHours.filter(function(val){return val == determineHour;});
Instead of
if( $.inArray(determineHour, stationRentalsHours[i])){
Try
if( $.inArray(determineHour, stationRentalsHours) != -1){
Your commented out code would do the trick with a slight amendment to the if condition. Your original condition was comparing a string to an array instead of an individual element in that array:
function updateChart() {
if(canvas3){
canvas3.destroy();
}
var determineHour = selectNumber.options[selectNumber.selectedIndex].innerHTML;
for (var i = 0; i < stationRentalsHours.length; i++){
if(determineHour == stationRentalsHours[i]){
stationRentalsHoursTemp.push(stationRentalsHours[i]);
}
}
}

Split a String Array and Store Values for each Iteration

So the variable classList stores all classes for the body. I then created a variable classListLength that has the length of classList so I can iterate through each index and then split each class. I do not know how to store the splits for each index as it loops through classList. Help me please.
var classList = jQuery('body').attr('class').split(' ');
var classListLength = classList.length;
var keyWords = function(array) {
for (var i = 0; i < classListLength; i++ ) {
classList[i].split('-');
}
}
if i do the following in the console
var keyWords = function(array) {
for (var i = 0; i < classListLength; i++ ) {
console.log(classList[i].split('-'));
}
}
I can see exactly what I want but I want to be able to store that and check it later on with a conditional.
var splitClassList = classList.map(function (class) {
return class.split('-');
});
So I solved what I needed. The below code allows me to iterate through my split classList. I then check the the specific class I want within the classList using .includes method and execute what I need done. If you guys know how to make this a bit more modular please chime in.
var brandClass
// Iterate though split classes
jQuery.each( classList, function(i) {
if ( classList[i].includes('product-wildridge') ) {
brandClass = classList[i];
}
});
// check specific class for certin keywords
var customTab = function(brandClass) {
if (brandClass.includes('wildridge') && brandClass.includes('deep') ) {
return true;
} else {
jQuery('#tab-fabric').css('display', 'none');
}
}
customTab(brandClass);

How to match and remove an object from javascript array?

I am trying to delete an element based on string match for a object property but when I do a slice on the javascript array the array size decreases and indexes change. Please help e with a solution. Here is a jsfiddle link for the same.
Code
var selection = JSON.parse('[{"Connectors":"c1"},{"Connectors":"c2"},{"Schedules":"s1"},{"Schedules":"s2"},{"Gauges":"g1"},{"Gauges":"g2"},{"Gauges":"g3"}]');
removeitem("Gauges");
function removeitem(item) {
for (var i = 0; i < selection.length; i++) {
if (selection[i].hasOwnProperty(item)) {
selection.splice(i, 1);
}
}
}
Add i--;
function removeitem(item) {
for (var i = 0; i < selection.length; i++) {
if (selection[i].hasOwnProperty(item)) {
selection.splice(i, 1);
i--;
}
}
}
jsfiddle example
Assuming you don't have a problem with having undefined as the new value, then you could call delete[i]; instead of selection.splice(i, 1); in that case the length does not change and neither will the indices.
Both Abhi1964 and Loolooii solution seems to work fine and solve problem, but i would personally keep the filtered results in separate array instead of manipulating index/deleting value in the same array, reason being, separate array would make code look simpler to read and understand. Reviewer need not to understand the index manipulation or keep track of undefined.
var selection = JSON.parse('[{"Connectors":"c1"},{"Connectors":"c2"},{"Schedules":"s1"},{"Schedules":"s2"},{"Gauges":"g1"},{"Gauges":"g2"},{"Gauges":"g3"}]');
removeitem("Gauges");
var filteredResult = [];
function removeitem(item) {
for (var i = 0; i < selection.length; i++) {
if (selection[i].hasOwnProperty(item)) {
}else{
filteredResult.push(item);
}
}
}
//use filtered result as per your need.
Note:
I have not run this code, if some error seems to be there, please feel free to edit.

Handling Duplicate objects in Javascript

I have a javascript method which handles removing from one select box to another.
The code runs as follows :
function moveAllOptions(formName, selectId1, selectId2) {
var sourceSelect = eval("document." + formName + "." + selectId1);
var destSelect = eval("document." + formName + "." + selectId2);
for (var i = 0; i < sourceSelect.length; i++) {
var optionText = sourceSelect.options[i].text;
var optionValue = sourceSelect.options[i].value;
for (var j = 0; j < destSelect.length; j++) {
if (destSelect.options[j].value == optionValue) {
destSelect.options[j].value = null;
}
}
}
}
But I found a problem like when it encounters duplicate values it is not deleting all the values .For eg: in the view source I have
value="139">Customer Service<
value="231">Customer Service<
value="231">Customer Service<
value="231">Customer Service<
value="231">Customer Service<
In this case it removes only two objects from my left hand box.
Is there any way to remove duplicate objects also.One way I could think is create an two array objects(Two Dimensional), pass all the values in left hand side to one array then iterate to another array and finally pass again to normal options.
Well, first of all the eval to hunt elements is horrible. There are far better ways of doing this starting with getElementById.
As to your actual problem, again there are simpler native ways to do this: the add and remove methods of the select object (reference). Try this method to start with.
function transferOptions(A, B)
{
var a = document.getElementById(A);
var b = document.getElementById(B);
while(a.options.length)
{
var x = a.options[0]; //store the value
a.remove(0); //remove it from the DOM
b.add(x); //reinsert it (adds to end of list)
}
}
transferOptions('select1','select2') //usage
for (var j = 0; j < destSelect.length; j++) {
if (destSelect.options[j].value == optionValue) {
destSelect.options[j].value = null;
}
}
Let's say the first item matched. You set destSelect.options[0].value to null, which effectively removes the first option from the list. Next you check destSelect.options[1], which is actually the third option in the original list. The second option has just become first, and occupies destSelect.options[0].
The way to avoid this problem is to go backwards, starting with the last item in the list and working up to the first.
for (var j = destSelect.length-1; j >=0; j--) {
if (destSelect.options[j].value == optionValue) {
destSelect.options[j].value = null;
}
}

Why is my nested for loop not working as I expected?

I have trouble dealing with my for loops now, I'm trying to compare two datum, basically it will compare 2 items, then it will write the matches and the mismatches on the webpage.
I managed to write the matches on the webpage, it was working good. But there's a bug in my mismatch compare.
It wrote all the data on the webpage X times, here's my JS code:
function testItems(i1, i2) {
var newArray = [];
var newArray2 = [];
var count = 0;
var count2 = 0;
for(var i = 0; i < i1.length; i++) {
for(var j = 0; j < i2.length; j++) {
if(i1[i] == i2[j]) {
newArray.push(i1[i]);
count++;
} if (i1[i] !== i2[j]) {
newArray2.push(i1[i]);
count2++;
}
}
}
count-=2;
count2-=2
writeHTML(count,count2, newArray, newArray2);
}
The result was horrible for the mismatches:
alt text http://www.picamatic.com/show/2009/03/01/07/44/2523028_672x48.jpg
I was expecting it to show the mistakes, not all the strings.
The issue you're seeing is because of the nested for loop. You are essentially doing a cross-compare: for every item in i1, you are comparing it to every item in i2 (remember that j starts again at 0 every time i advances... the two loops don't run in parallel).
Since I understand from the comments below that you want to be able to compare one array to the other, even if the items in each are in a different order, I've edited my original suggestion. Note that the snippet below does not normalize differences in case between the two arrays... don't know if that's a concern. Also note that it only compares i1 against i2... not both i1 to i2 and i2 to i1, which would make the task a little more challenging.
function testItems(i1, i2) {
var newArray = [];
var newArray2 = [];
for (var i = 0; i < i1.length; i++) {
var found = false;
for (var j = 0; j < i2.length; j++) {
if (i1[i] == i2[j]) found = true;
}
if (found) {
newArray.push(i1[i])
} else {
newArray2.push(i1[i])
}
}
}
As an alternative, you could consider using a hash table to index i1/i2, but since the example of strings in your comment include spaces and I don't know if you're using any javascript helper libraries, it's probably best to stick with the nested for loops. The snippet also makes no attempt to weed out duplicates.
Another optimization you might consider is that your newArray and newArray2 arrays contain their own length property, so you don't need to pass the count to your HTML writer. When the writer receives the arrays, it can ask each one for the .length property to know how large each one is.
Not directly related to the question but you should see this:
Google techtalks about javascript
Maybe it will enlighten you :)
Couple of things about your question. First you should use '!=' instead of '!==' to check inequality. Second I am not sure why you are doing decreasing counts by 2, suggests to me that there may be duplicates in the array?! In any case your logic was wrong which was corrected by Jarrett later, but that was not a totally correct/complete answer either. Read ahead.
Your task sounds like "Given two set of arrays i1 & i2 to find i1 {intersection} i2 and i1{dash} {UNION} i2{dash}) (Group theory notation). i.e. You want to list common elements in newArray and uncommon elements in newArray2.
You need to do this.
1) Remove duplicates in both the arrays. (For improving the program efficiency later on) (This is not a MUST to get the desired result - you can skip it)
i1 = removeDuplicate(i1);
i2 = removeDuplicate(i2);
(Implementation for removeDuplicate not given).
2) Pass through i1 and find i1{dash} and i1 {intersection} i2.
var newArray = [];
var newArray2 = [];
for (var i = 0; i < i1.length; i++)
{
var found = false;
for (var j = 0; j < i2.length; j++)
{
if (i1[i] == i2[j])
{
found = true;
newArray.push(i1[i]); //add to i1 {intersection} i2.
count++;
break; //once found don't check the remaining items
}
}
if (!found)
{
newArray2.push(i1[i]); //add i1{dash} to i1{dash} {UNION} i2{dash}
count2++;[
}
}
3) Pass through i2 and append i2{dash} to i1{dash}
for(var x=0; x<i2.length; x++)
{
var found = false;
//check in intersection array as it'd be faster than checking through i1
for(var y=0; y<newArray.length; y++) {
if( i2[x] == newArray[y])
{
found = true;
break;
}
}
if(!found)
{
newArray2.push(i2[x]); //append(Union) a2{dash} to a1{dash}
count2++;
}
}
writeHTML(count,count2, newArray, newArray2);
I have a feeling that this has to do with your second comparison using "!==" instead of "!="
"!==" is the inverse of "===", not "==". !== is a more strict comparison which does not do any type casting.
For instance (5 != '5') is false, where as (5 !== '5') is true. This means it's possible that you could be pushing to both arrays in the nested loop, since if(i1[i] == i2[j]) and if(i1[i] !== i2[j]) could both be true at the same time.
The fundamental problem here is that a pair of nested loops is NOT the right approach.
You need to walk a pointer through each dataset. ONE loop that advances both as needed.
Note that figuring out which to advance in case of a mismatch is a much bigger problem than simply walking them through. Finding the first mismatch isn't a problem, getting back on track after finding it is quite difficult.

Categories

Resources