Remove Duplicates from Jquery - javascript

I have two strings like below and I need to remove the duplicates.
I.E., I need to remove/ignore the common elements in both the strings and show only the difference.
var char1 = "AAA-BBB|BBB-CCC|CCC-AAA";
var char2 = "AAA-BBB|BBB-CCC";
var removeDuplicates = //<-- Here I need CCC-AAA only
Here I have tried it,
var Joined = char1 + "|" + char2;
var removeDuplicates = $.unique(Joined.split('|')); //<-- Result : "AAA-BBB|BBB-CCC|CCC-AAA";

jQuery's $.grep can be used to remove all duplicates in an array
var char1 = "AAA-BBB|BBB-CCC|CCC-AAA";
var char2 = "AAA-BBB|BBB-CCC";
var removeDuplicates = $.grep(char1.split('|'), (function(y) {
return function(item) { return $.inArray(item, y) === -1 }
})(char2.split('|')));
console.log( removeDuplicates );
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

You can simply make an array from the parameters and Array#filter() the array one returning only the elements that are not in the second array with Array#indexOf():
var char1 = "AAA-BBB|BBB-CCC|CCC-AAA",
char2 = "AAA-BBB|BBB-CCC",
removeDuplicates = function(str1, str2) {
var arr1 = str1.split('|'),
arr2 = str2.split('|');
return arr1.filter(function(item) {
return arr2.indexOf(item) === -1;
});
};
console.log(removeDuplicates(char1, char2));

Related

Function is meant to be non-destructive but it is modifying my variable

I have the following code which sets special to run a function convertSpecial which will replace the apostrophe in array1 with a provided character. In this case, a space. Since the replacing character is a space, it will split that element into two then flatten the array. It will then check to see if any element in special matches any element in array2. This will return false. It will then replace the apostrophe with no character at all and recheck against array2.
The idea behind convertSpecial and the variable special is that it should be non-destructive to array1, but this isn't happening as you can see:
var array1 = ["o'hara"];
var array2 = ["ohara"];
var special = '';
function convertSpecial(a,b,c) {
var aCopy = a;
for (let i = 0; i < aCopy.length; i++) {
if (aCopy[i].includes(b)) {
if (c == '') {
aCopy[i] = aCopy[i].replace(b,c);
} else {
aCopy[i] = aCopy[i].replace(b,c).split(' ');
aCopy = aCopy.flat();
}
}
}
return aCopy;
}
console.log('array1 1 = '+array1); // returns array1 1 = o'hara as expected
special = convertSpecial(array1,"'"," ");
console.log('array1 2 = '+array1); // returns array1 2 = o,hara THIS SHOULD NOT HAVE BEEN MODIFIED
console.log('special 1 = '+special); //returns special 2 = o,hara as expected
if (array2.some(v => special.includes(v)) == true) {
console.log('array1 3 = '+array1); // ignored as expected
array1 = specialDECln;
} else {
console.log('array1 4 = '+array1); //returns array1 4 = o,hara THIS SHOULD NOT HAVE BEEN MODIFIED
special = convertSpecial(array1,"'","");
console.log('array1 5 = '+array1); //returns array1 5 = o,hara THIS SHOULD NOT HAVE BEEN MODIFIED
console.log('special 2= '+special); //returns special 2 = o,hara should be ohara
if (array2.some(v => special.includes(v)) == true) {
array1 = special;
}
}
console.log(array2 == special); //returns false, should be true because expected ohara = ohara
Everything works as it should, EXCEPT array1 is being modified when it shouldn't be at all. Since it gets modified, special gets set to an incorrect value.
What am I doing wrong and how can I fix it?
You need to clone that array in order to avoid mutation. There are a lot of ways for doing that, an alternative is using the Spread-syntax as follow:
let result = [...a]; // This creates a new array with the index-values from array a.
var array1 = ["o'hara"];
var special = ''
console.log("array1 = " + array1); // returns array1 = o'hara as expected
function convertSpecial(a, b, c) { // a = array, b = character to replace, c = character to replace with
let result = [...a];
for (let i = 0; i < result.length; i++) {
if (result[i].includes(b)) {
if (c == '') {
result[i] = result[i].replace(b, c);
} else {
result[i] = result[i].replace(b, c).split(' ');
result = result.flat();
}
}
}
return result;
}
special = convertSpecial(array1, "'", " ");
console.log("array1 = " + array1); // returns array1 = o, hara but it should be o'hara
console.log("special = " + special); // returns special = o, hara as expected
You need to duplicate the array first:
var array1 = ["o'hara"];
var special = ''
console.log("array1 = " + array1); // returns array1 = o'hara as expected
function convertSpecial(a, b, c) { // a = array, b = character to replace, c = character to replace with
var aCopy = a.slice();
for (let i = 0; i < aCopy.length; i++) {
if (aCopy[i].includes(b)) {
if (c == '') {
aCopy[i] = aCopy[i].replace(b, c);
} else {
aCopy[i] = aCopy[i].replace(b, c).split(' ');
aCopy = aCopy.flat();
}
}
}
return aCopy;
}
special = convertSpecial(array1, "'", " ");
console.log("array1 = " + array1); // returns array1 = o, hara but it should be o'hara
console.log("special = " + special); // returns special = o, hara as expected

Finding letters in 2nd array element in 1st array element

Using javascript, I want to check if the string in the 1st array element contains all the letters of the 2nd array element. If so, return true. E.g. ["Mary", "Aarmy"] => true;
["hello", "hey"] => false.
I've tried the following code, which works for ["Mary", "Aarmy"] and ["voodoo", "no"], but doesn't work for ["hello", "hey"]. Appreciate any help, thanks!
function mutation(arr){
var str1 = arr.pop().toLowerCase();
var str2 = arr.pop().toLowerCase();
for(var i = 0; i < str2.length; i++){
if(str1.indexOf(str2[i]) !== -1){
return true;
}
else return false;
}
}
When you use pop() it'll return the last element in the array and not the first.
Also your if else is inside for and has a return statement. This does not let the for loop run completely and returns after the very first loop.
function mutation(arr){
var str2 = arr.pop().toLowerCase();
var str1 = arr.pop().toLowerCase();
console.log("str1: " + str1);
console.log("str2: " + str2);
for(var i = 0; i < str2.length; i++){
if(str1.indexOf(str2[i]) === -1){
return false;
}
}
return true;
}
arr = ["hello", "hey"];
console.log(mutation(arr));
arr = ["Mary", "Aarmy"];
console.log(mutation(arr));
Considering you can use Set, and lodash, here is another solution:
const _ = require("lodash");
function mutation(arr) {
var set1 = new Set(arr.pop().toLowerCase().split(''));
var set2 = new Set(arr.pop().toLowerCase().split(''));
return _.isEqual(set1, set2);
}
console.log(mutation(["Mary", "Aarmy"])); //true
console.log(mutation(["hello", "hey"])); //false
console.log(mutation(["voodoo", "no"])); //false
Check the working sample: https://jsfiddle.net/sayan751/3q8rtqy3/
Recursively, just for sport. If you're dealing with long (>100 char) strings, this is risky, as it relies on stack space.
const contains = function (a, b) {
if (!b) return true;
return a.indexOf(b[0]) !== -1 && contains(a, b.substring(1));
}
console.log(contains('mary', 'army')); // true
console.log(contains('hello', 'hey')); // false
Split and sort to speed up things - now only ONE comparison per set
var arr = ["Mary", "Aarmy","hello", "hey", "voodoo", "no"]
function mutation(){
var str1 = arr.pop().toLowerCase().split("").sort().join("");
var str2 = arr.pop().toLowerCase().split("").sort().join("");
return str1.indexOf(str2) !=-1;
}
while (arr.length) console.log(arr[arr.length-2],mutation())
How could function return more than one value ;) (line 6) And if second array has an array length of 3 it just checks the first arrays 3 elements. (line 4)
function mutation(arr) {
var set1 = arr[0].toLowerCase();
var set2 = arr[1].split('');
return set2.every(function(element, index, array){
if(set1.indexOf(element.toLowerCase()) != -1)
return true;
else
return false;
});
}
console.log(mutation(["Mary", "Aarmy"])); //return true
console.log(mutation(["hello", "hey"])); //return false
console.log(mutation( ["voodoo", "no"])); //return false
console.log(mutation( ["voodoo", "vo"])); //return true

JQuery remove duplicate from array where string contains same text

I have an array with X number of items. Each has variables separated by a pipe character. In a loop I can split on the pipe to get the second item; but how do I splice to remove the duplicate.
"Sometext|22621086|address|333629dc87894a7ea7df5291fa6d1836|PC_E|1803"
"Sometext2|22622138|working|d3e70175ffe942568cd21f1cf96f4d63|PC_E|1803"
"Sometext3|22622138|working|851946e6325445da99c113951590f714|PC_E|1803"
Results should be this.
"Sometext|22621086|address|333629dc87894a7ea7df5291fa6d1836|PC_E|1803"
"Sometext2|22622138|working|d3e70175ffe942568cd21f1cf96f4d63|PC_E|1803"
Note that the duplicate 22622138 is a random number so the solution needs to work for any number in this location (it's always in the arr[1] position).
This is what I tried:
$.each(arr_transcript, function (i, e) {
if (e.length != 0) {
var arr = e.split("|")
var i = arr_transcript.indexOf(arr[1]);
if (i != -1) {
arr_transcript.splice(i, 1);
}
}
});
Here's a generic function:
function uniqBy(a, key) {
let seen = new Set();
return a.filter(item => {
let k = key(item);
return !seen.has(k) && seen.add(k);
});
};
var data = [
"Sometext|22621086|address|333629dc87894a7ea7df5291fa6d1836|PC_E|1803",
"Sometext2|22622138|working|d3e70175ffe942568cd21f1cf96f4d63|PC_E|1803",
"Sometext3|22622138|working|851946e6325445da99c113951590f714|PC_E|1803"
];
var result = uniqBy(data, item => item.split('|')[1]);
console.log(result)
See here for more info.
Create a map of the numbers you want to check against, and then filter based on that
var arr_transcript = [
"Sometext|22621086|address|333629dc87894a7ea7df5291fa6d1836|PC_E|1803",
"Sometext2|22622138|working|d3e70175ffe942568cd21f1cf96f4d63|PC_E|1803",
"Sometext3|22622138|working|851946e6325445da99c113951590f714|PC_E|1803"
];
var map = arr_transcript.map(function(text) {
return text.split('|')[1];
});
var filtered = arr_transcript.filter(function(item, index) {
return index === map.lastIndexOf( map[index] );
});
console.log(filtered)

Integer arrays comparison

I have a question of JS arrays.
Example:
var fullArr = [1,2,3,4];
var partArr = [2,3];
var newArr = [];
We have a main array fullArr and a partial array partarr. I want to create a function/filter, which is looking for existing items in fullArr and not in partArr.
In this example above newArr must be equal to [1,4].
I've tried doing something like this, but it's not working properly.
for (var k in fullArray) { // [1,2,3,4]
for (var j in selectedArray) { // [1,4]
if (fullArray[k] == selectedArray[j]) {
newArray.splice(selectedArray[j] - 1, 1); // must be [2,3]
break;
}
}
}
What is a good way of making this? Thanks.
Here's one
var newArr = fullArr.filter(function(f) { // The filter() method creates a new array with all elements that pass the test implemented by the provided function.
return partArr.indexOf(f) == -1; // The indexOf() method returns the first index at which a given element can be found in the array, or -1 if it is not present.
})
to impress the girls, you can also
var newArr = fullArr.filter(function(f) {
return !~partArr.indexOf(f);
})
Here is the code for your requirement.
var fullArr = [1,2,3,4];
var partArr = [2,3];
var newArr = [];
for(var i=0;i<fullArr.length;i++){
if(partArr.indexOf(fullArr[i]) == -1)
newArr.push(fullArr[i]);
};
Here is the working Link
Hope it works :)
In fact, you want a common part between arrays. Obviously you can choose splice or indexOf to have O(n * m) or even O(m * n^2) performance. It's obviously suboptimal for any array larger than few elements
Or you can use objects as hash maps to find differences in (in worst case) O(n + m log m):
var fullArr = [1,2,3,4];
var partArr = [2,3];
var temporaryObject = Object.create(null);
partArr.forEach(el=>temporaryObject[el] = true); // temporaryObject after this operation is {"2": true, "3": true}
var newArr = fullArr.filter(el=>temporaryObject[el]);
In this example I have used ES6 feature called "arrow functions". It translates to following ES5 code:
var partArr = [2, 3];
var temporaryObject = Object.create(null);
partArr.forEach(function (el) {
temporaryObject[el] = true;
}); // temporaryObject after this operation is {"2": true, "3": true}
var newArr = fullArr.filter(function (el) {
return temporaryObject[el];
});
You can use the filter() function that works on arrays:
var newArr = fullArr.filter(function(val, i, arr) {
return partArr.indexOf(val) === -1;
});
This will return a new array containing the values of every iteration that returns true.
Should you ever need to do this on an object in the future a great way is to first convert the object keys to an array and then run the filter:
Object.keys(myObj).function(val, i, arr) {
return partArr.indexOf(val) === -1;
});
Here are few other approaches:
var fullArr = [1,2,3,4];
var partArr = [2,3];
var newArr = [];
1.
fullArr.map(function(element){
if(partArr.indexOf(element) === -1) newArr.push(element);
})
console.log(newArr);
2.
for(i in fullArr){
if(partArr.indexOf(fullArr[i]) === -1) newArr.push(fullArr[i]);
}
console.log(newArr);
3.
fullArr.forEach(function(element){
if(partArr.indexOf(element) === -1) newArr.push(element);
})
console.log(newArr);

How to find the string that matches in array?

I would like to get the full string element from an array that matches multiple substrings in no particular order. If more than one match, an exception should be thrown.
var thisArray = [ '/something_else/', '/and_something_else/', '/and_something_else_here/'];
var thisMatch = [ 'some', 'and', 'here'];
var matchingElement = new RegExp(thisArray , thisMatch); // Not sure about this
What I want is for matchineElement to contain the string "and_something_else_here" after the regular expression has executed.
You could do something like this:
var thisArray = [ '/something_else/', '/and_something_else/', '/and_something_else_here/'];
var thisMatch = [ 'some', 'and', 'here'];
function matchElements(arr, arrMatch) {
var tmpArr;
arrMatch.forEach(function(el, i, a) {
tmpArr = arr.filter(function(str) {
return str.indexOf(el) !== -1;
});
});
if (tmpArr.length > 1) {
throw ("Hey, too many matches");
} else {
return tmpArr[0];
}
}
console.log(matchElements(thisArray, thisMatch));
JSFiddle: http://jsfiddle.net/Le53y7ee/
Explanation:
The function goes through every element in the array containing substrings and filters main array keeping only strings that match. After the loop is done the array should contain only string(s) that matched all required substrings.
A regexp that matches a string containing all of a set of substrings looks like:
^(?=.*?string1)(?=.*?string2)(?=.*?string3).*$
So you just need to convert your thisMatch array into such a regular expression.
var regexp = new RegExp('^' + thisMatch.map(function(x) {
return '(?=.*?' + x + ')';
}).join('') + '.*$');
Then you can find all the matches with:
var matchingElements = thisArray.filter(function(x) {
return regexp.test(x);
});
if (matchingElements.length != 1) {
throw new Error('Single match not found');
} else {
matchingElement = matchingElements[0];
}
DEMO
Try
var matchingElement = thisArray.filter(function(val, key) {
var value = val.split(/[^a-z]/).filter(String).join(" ");
// if `.test()` returns `true` three times at `value`
return new RegExp(this[0]).test(value)
&& new RegExp(this[1]).test(value)
&& new RegExp(this[2]).test(value)
? val
: null
}.bind(thisMatch))[0].replace(/\//g,"");)
var thisArray = [ '/something_else/', '/and_something_else/', '/and_something_else_here/'];
var thisMatch = [ 'some', 'and', 'here'];
var matchingElement = thisArray.filter(function(val, key) {
var value = val.split(/[^a-z]/).filter(String).join(" ");
// if `.test()` returns `true` three times at `value`
return new RegExp(this[0]).test(value)
&& new RegExp(this[1]).test(value)
&& new RegExp(this[2]).test(value)
? val
: null
}.bind(thisMatch))[0].replace(/\//g,"");
document.write(matchingElement)
Take those slashes off of both sides of your Strings in those Arrays. Then use the arrayMatch function below, and loop over your indexes to get the results of thisArray, like:
function arrayMatch(yourArray, wordMatchArray){
var ix = [], c = wordMatchArray.length;
for(var i=0,l=yourArray.length; i<l; i++){
var m = 0;
for(var n=0; n<c; n++){
if(yourArray[i].match(new RegExp(wordMatchArray[n])))m++;
if(c === m)ix.push(i);
}
}
if(!ix[0]){
return false;
}
return ix;
}
var indexes = arrayMatch(thisArray, thisMatch);
for(var i=0,l=indexes.length; i<l; i++){
var getMatch = thisArray[indexes[i]];
}

Categories