JavaScript Replace matching members of array compared to other array - javascript

I got this task and I can't get how to replace the matches with the string "BUSTED", can you help me please. I'm new to JS. Most probably there is a way more elegant way to do this. Any help appreciated.
You're given two arrays: one that holds every member of fCommunity and another one
that holds every possible suspect.
Replace every fCommunity member from the Suspect list with the word "BUSTED"
var fCommunityMembers = ['A','B','C'];
var SuspectList = ['F','X','B','Z','Y','C','ZS','D','K','M','N'];
I managed to retrieve the matching members but how do I replace them in the suspect list?:
Array.prototype.diff = function(SuspectList) {
var ret = [];
this.sort();
SuspectList.sort();
for(var i = 0; i < this.length; i += 1) {
if(SuspectList.indexOf( this[i] ) > -1){
ret.push( this[i] );
}
}
return ret;
};
var ListOfMatches = Array.from(fCommunityMembers.diff(SuspectList));
console.log( ListOfMatches );

Use Array.prototype.map() to iterate fCommunityMembers. If an member is found in the SuspectList return BUSTED, if not return the member:
var fCommunityMembers = ['A','B','C'];
var SuspectList = ['F','X','B','Z','Y','C','ZS','D','K','M','N'];
var result = fCommunityMembers.map(function(member) {
return SuspectList.indexOf(member) !== -1 ? 'BUSTED' : member;
});
console.log(result);

What you need is a function that can do the intersection between two arrays
filter can help in your case
var fCommunityMembers = [
'A',
'B',
'C',
'D',
'F'
];
var SuspectList = [
'F',
'X',
'B',
'Z',
'Y',
'C',
'ZS',
'D',
'L'
];
var suspects= fCommunityMembers.filter(function(el){
return SuspectList.indexOf(el)>-1;
});
Edit #1
To replace the values by busted, do the following:
var suspectsFnc = function (fc, sus) {
var busted = fCommunityMembers.filter(function (el) {
return SuspectList.indexOf(el) > -1;
});
for (var i = 0; i < fc.length; i++) {
if (busted.indexOf(fc[i]) > -1) {
fc[i] = "Busted";
}
}
return fc;
}
var suspects = suspectsFnc(fCommunityMembers, SuspectList);

Judt use filter like this :
var ListOfMatches = SuspectList.filter(x => fCommunityMembers.indexOf(x) !== -1);
and a forEach loop to insert BUSTED instead of previous matched elements
fCommunityMembers.forEach((x,i,arr) => {
if (SuspectList.indexOf(x) !== -1)
arr[i] = "BUSTED";
});

Related

there is an string array A , and an string array B . I want to delete elements in A which are not in B

I think i messed somewhere, Here is my code.
var flag;
for (i = 0; i < A.length; i++)
{
flag = 0;
for (j = 0; j < B.length; j++)
{
if (A[i].indexOf(B[j]) != -1)
{
flag = 1;
}
}
if (flag == 0)
{
A.splice(i, 1);
}
}
It gives output not as per my need
Someone please Help me out
I would do the job like this;
//returns intersection of multiple arrays
Array.prototype.intersect = function(...a) {
return [this,...a].reduce((p,c) => p.filter(e => c.includes(e)));
};
var a = [0,1,2,3,4,5],
b = [4,5,6,7,8,9];
a = a.intersect(b);
console.log(a);
You could use a function which generates first an object with all characters as properties and take it as hashtable for the filtering of array1.
function deleteSome(array1, array2) {
var o = Object.create(null);
array2.forEach(function (a) {
o[a] = true;
});
return array1.filter(function (a) {
return this[a];
}, o);
}
var a = 'abcdefgh'.split(''),
b = 'banana'.split('');
console.log(deleteSome(a,b));
Technically, array "a" should have only elements which are present in array "b".
var a = [1,2,3,4];
var b = [4,5,6];
var new_a = [];
a.map(function(v,i,a){
if(b.indexOf(v) !== -1){
new_a.push(v);
}
});
console.log(new_a); //[4]
By this way i can filter as many arrays as you want.
var a = ['A', 'A', 'R', 'S', 'M', 'D', 'E']
var b = ['C', 'X', 'D', 'F']
//you can add as many arrays as you want
/*var c = ['O', 'P', 'D', 'Q']
var d = ['R', 'D', 'D', 'Z']*/
var arrays = [a,b, /*c , d */];
var result = arrays.shift().filter(function(v) {
return arrays.every(function(a) {
return a.indexOf(v) !== -1;
});
});
console.log(JSON.stringify(result));

Combining some array items

I'm kind of new to functional programming and I try to do the following: Let's say I have an array of values: ['a','b-','c'] and I want that every item which ends with a '-' is merged with the following array entry: ['a','b-c'].
Of course I can do this by making a for-loop:
var test = ['a', 'b-', 'c'], result = [];
for (var i=0;i<test.length;i++) {
var curr = test[i];
if (curr.endsWith('-')) {
curr += test[i+1];
i++;
}
result.push(curr);
}
But how can one do this without the for loop?
To be honest, the way you programmed is probably the most efficient way to do this.
However, here's another option:
var test = ['a', 'b-', 'c'],
result = test.join().replace(/-,/g, '').split(',');
console.log(result);
This joins all elements into a string: 'a,b-,c', removes all occurrences of '-,' > 'a,bc', then splits the string back up into an array with the desired result, as you can see in the output.
This can be fool-proofed a bit, by changing the separator used in the join / split:
var test = ['a', 'b-', 'c'],
separator = '||',
result = test.join(separator)
.replace(new RegExp('-' + separator, 'g'), '')
.split(separator);
One possible approach (with .reduce):
var arr = ['a', 'b-', 'c'];
var trans = arr.reduce(function(acc, cur) {
if (acc.length && acc[acc.length - 1].slice(-1) === '-') {
acc[acc.length - 1] += cur;
}
else {
acc.push(cur);
}
return acc;
}, []);
This can also be achieved using Array.prototype.map:
var test = ['a', 'b-', 'c'];
var result = test.slice().map(function (x, i, a) {
if (x.endsWith("-") && a[i+1]) {
var r = x + a[i+1]; // Join this and the next element in the array
a.splice(i, 1); // Remove the next element from the array
return r;
}
return x;
}).filter(function (x) {
return typeof x !== 'undefined';
}); // Since the array comes back with a different length and some undefined elements, remove those. Thanks #Cerbrus for pointing this out
console.log(test, result, result.length); // ["a", "b-", "c"] ["a", "b-c"] 2
This way will work for multiple dashed elements in a row, and if the last element has a dash, uses Array.forEach
var test = ['a', 'b-', 'c-'], result = [], next = "";
test.forEach(function(curr) {
if (curr.endsWith('-')) {
next += curr;
if (curr == test[test.length-1]) {
result.push(next);
}
}else {
result.push(next + curr);
next = "";
}
});
document.write(result);
Another map + filter one. Most likely slower, as filter add's another iteration through the array, but works as the original does (which is probably not what the OP wants when there are multiple -'s in a row).
var test = ['a', 'b-', 'c-', 'd', 'e'], result = [];
result = test
.map((curr, i, array) => (curr.endsWith('-') && array[i + 1] !== undefined) ? curr + array[i+1] : curr)
.filter((curr, i, arr) => (i>0 && arr[i-1].length > 1 && curr.length === 1) ? false : true)
document.write(result);
Didn't read all answers, so sry if I repeat sth. that has already been said.
Functional programming doesn't mean that there is always a predefined function that does exactly what you intend to; or a combination of some.
Sometimes it is better to write a simple short utility-function than abusing the ones that are already there.
How about some "problems" like multiple dashed-values next to each other, or at the end of the list? How do you want to handle these cases?
This would be my implementation:
function combineDashedStrings(arr){
var result = [], pending = ""
for (var i=0; i<arr.length; i++) {
var curr = pending + arr[i];
pending = curr.endsWith("-") && curr || ""; //multiple concats
//pending = !pending && curr.endsWith("-") && curr || ""; //single concat
pending || result.push(curr);
}
//pending && result.push(curr); //add last item if it contains a dash
return result
}
combineDashedStrings(['a', 'b-', 'c-', 'd', 'e-']);
feel free to switch the commented lines/options

Array.prototype.indexOf() cannot find array inside of multi-dimensional array [duplicate]

Let's say we have the following js array
var ar = [
[2,6,89,45],
[3,566,23,79],
[434,677,9,23]
];
var val = [3,566,23,79];
Is there a js builtin function or jQuery one with which you can search the array ar for val?
Thanks
***UPDATE*************
Taking fusion's response I created this prototype
Array.prototype.containsArray = function(val) {
var hash = {};
for(var i=0; i<this.length; i++) {
hash[this[i]] = i;
}
return hash.hasOwnProperty(val);
}
you could create a hash.
var ar = [
[2,6,89,45],
[3,566,23,79],
[434,677,9,23]
];
var hash = {};
for(var i = 0 ; i < ar.length; i += 1) {
hash[ar[i]] = i;
}
var val = [434,677,9,23];
if(hash.hasOwnProperty(val)) {
document.write(hash[val]);
}
You can also use a trick with JSON serializing. It is short and simple, but kind of hacky.
It works, because "[0,1]" === "[0,1]".
Here is the working demo snippet:
Array.prototype.indexOfForArrays = function(search)
{
var searchJson = JSON.stringify(search); // "[3,566,23,79]"
var arrJson = this.map(JSON.stringify); // ["[2,6,89,45]", "[3,566,23,79]", "[434,677,9,23]"]
return arrJson.indexOf(searchJson);
};
var arr = [
[2,6,89,45],
[3,566,23,79],
[434,677,9,23]
];
document.body.innerText = arr.indexOfForArrays([3,566,23,79]);
function indexOfArray(val, array) {
var hash = {};
for (var i = 0; i < array.length; i++) {
hash[array[i]] = i;
}
return (hash.hasOwnProperty(val)) ? hash[val] : -1;
};
I consider this more useful for than containsArray(). It solves the same problem (using a hash table) but returns the index (rather than only boolean true/false).
Can you try this?
var ar = [
[2,6,89,45],
[3,566,23,79],
[434,677,9,23]
];
var val = [3,566,23,79];
var sval = val.join("");
for(var i in ar)
{
var sar = ar[i].join("");
if (sar==sval)
{
alert("found!");
break;
}
}
Why don't you use javascript array functions?
function filterArrayByValues(array, values) {
return array.filter(function (arrayItem) {
return values.some(function (value) {
return value === arrayItem;
});
});
}
Or if your array is more complicated, and you want compare only one property but as result return whole object:
function filterArrayByValues(array, values, propertyName) {
return array.filter(function (arrayItem) {
return values.some(function (value) {
return value === arrayItem[propertyName];
});
});
}
More about used functions: filter() and some()
You can use Array.prototype.some(), Array.prototype.every() to check each element of each array.
var ar = [
[2, 6, 89, 45],
[3, 566, 23, 79],
[434, 677, 9, 23]
];
var val = [3, 566, 23, 79];
var bool = ar.some(function(arr) {
return arr.every(function(prop, index) {
return val[index] === prop
})
});
console.log(bool);
I guess there is no such JS functionality available. but you can create one
function arrEquals( one, two )
{
if( one.length != two.length )
{
return false;
}
for( i = 0; i < one.length; i++ )
{
if( one[i] != two[i] )
{
return false;
}
}
return true;
}
The problem with this is that of object/array equality in Javascript. Essentially, the problem is that two arrays are not equal, even if they have the same values. You need to loop through the array and compare the members to your search key (val), but you'll need a way of accurately comparing arrays.
The easiest way round this is to use a library that allows array/object comparison. underscore.js has a very attractive method to do this:
for (var i = 0; i < ar.length; i++) {
if (_.isEqual(ar[i], val)) {
// value is present
}
}
If you don't want to use another library (though I would urge you to -- or at least borrow the message from the Underscore source), you could do this with JSON.stringify...
var valJSON = JSON.stringify(val);
for (var i = 0; i < ar.length; i++) {
if (valJSON === JSON.stringify(ar[i]) {
// value is present
}
}
This will almost certainly be significantly slower, however.
You can use toString convertion to compare elements
var ar = [
[2,6,89,45],
[3,566,23,79],
[434,677,9,23]
];
var val = [3,566,23,79];
s = !ar.every(a => (a.toString() != val.toString()));
console.log(s) // true
Use this instead
if (ar.join(".").indexOf(val) > -1) {
return true;
} else {
return false;
}
Use lodash isEqual
const isValIncludedInAr = ar.some(element => isEqual(element, val))
const arrayOne = [2,6,89,45];
const arrayTwo = [3,566,23,79];
const arrayThree = [434,677,9,23];
const data = new Set([arrayOne, arrayTwo, arrayThree]);
// Check array if exist
console.log( data.has(arrayTwo) ); // It will return true.
// If you want to make a set into array it's simple
const arrayData = [...data];
console.log(arrayData); // It will return [[2,6,89,45], [3,566,23,79], [434,677,9,23]]

how to find an element in one of three array and then return the parent array name?

I am trying to check if an element exists in any one of three arrays. I don't know how to return the name of the array where the element was found. Can anyone direct me into the right direction please.
I have coded a function which takes the element in search as its argument and then returns the array name:
var arr1 = ['a','b','c','d'];
var arr2 = ['e','f','g','h'];
var arr3 = ['i','j','k','l'];
function chkElem(elem)
{
var id = elem;
var isFound = null;
if(arr1.indexOf(id) || (arr2.indexOf(id) || (arr3.indexOf(id))))
{
isFound = ????
}
return isFound;
}
I am uncertain how to assign the parent array name to 'isFound' variable.
Thanks.
You should never use "variable names" in your function logic. Instead, make the arrays properties of an object and return the property name:
var arrays = {
"arr1": ['a','b','c','d'],
"arr2": ['e','f','g','h'],
"arr3": ['i','j','k','l']
};
for (var name in arrays)
if (arrays[name].indexOf(id) > -1)
return name;
return null;
Or, even better, use an array of arrays to search in and return the index:
var arrays = [
['a','b','c','d'],
['e','f','g','h'],
['i','j','k','l']
];
for (var i=0; i<arrays.length; i++)
if (arrays[i].indexOf(id) > -1)
return i;
return -1;
Test one-by-one:
if (arr1.indexOf(id) > -1) {
isFound = arr1;
} else if (arr2.indexOf(id) > -1) {
isFound = arr2;
} else if (arr3.indexOf(id) > -1) {
isFound = arr3;
}
Alternatively, create a multi-dimensional array:
var arr = [
['a','b','c','d'],
['e','f','g','h'],
['i','j','k','l']
];
var isFound = null;
for (var i = 0; i < arr.length; i++) {
if (arr[i].indexOf(elem) > -1) {
isFound = arr[i];
break;
}
}
Firstly, be careful of the indexOf() trap - if it fails to find the requested string, it will return -1 - which is a truthy - so you need to check explicitly like so:
if (arr1.indexOf(id) != -1)
not
if (arr1.indexOf(id))
The truthy/falsy concept also means that, if your string is the first element in the array, and so indexOf() returns false, that is a falsy, and so your condition will actually fail even though a match was made!
Secondly, you cannot return the name of the array - or, to be more precise, the name of the variable that references it in the JS memory. You can either:
1) return the array itself
if (arr1.indexOf(id) != -1) return arr1;
2) store your arrays in a central object and return the name of the property that you found it in
var arrs = {
'one': ['foo', 'bar']
/* two, three etc */
};
for(var i in arrs)
if (arrs[i].indexOf('foo') != -1)
return i;
When you have a group of things, store them in an array (if they are ordered) or an object (if they are named). If you spot a bunch of variables with almost identical names, you're probably doing something wrong.
var things = [
['a','b','c','d'],
['e','f','g','h'],
['i','j','k','l']
];
Then you can loop over them:
for (var i = 0; i < things.length; i++) {
var thing = things[i];
if (thing.indexOf(id) > -1) { // indexOf returns -1 if not found, and the index (starting from 0) if it is.
return i;
}
}
return null;
var arr1 = ['a', 'b', 'c', 'd'];
var arr2 = ['e', 'f', 'g', 'h'];
var arr3 = ['i', 'j', 'k', 'l'];
function chkElem(elem) {
var isFound;
(isFound = arr1).indexOf(elem) > -1 || (isFound = arr2).indexOf(elem) > -1 || (isFound = arr3).indexOf(elem) > -1;
return isFound;
}
alert(chkElem('f'));

Function to return distinct values in a 2D array

I have the following 2D array
var items = [['al','bv','sd'],
['al','cc','ab'],
['cv','vv','sw'],
['al','bv','sd']
];
I need a function which will return me a similar array but with distinct values. For example, in the above array, ['al','bv','sd'] happens twice.
I would like the function to return me:
var items = [['al','bv','sd'],
['al','cc','ab'],
['cv','vv','sw']
];
Quick and dirty solution, assuming the data is small.
On each iteration, convert the row to a string. Use a dictionary to store the string with a value of True, if it is not already in the map. Also, add it to your output array. If it is already in the dictionary, go to the next item.
Example:
var d = {};
var out = [];
for( var i = 0; i < items.length; i++ ) {
var item = items[i];
var rep = item.toString();
if (!d[rep]) {
d[rep] = true;
out.push(item);
}
}
// out has the result
You have to loop two (or three times):
Loop through all "rows", from beginning to the end
Loop again, through all "rows", from beginning to the end
If the lists are equal, ignore it
Otherwise,
Loop through all "columns":
If the values are not equal, jump to the parent loop.
After the loop, remove the element using the .splice method.
Demo: http://jsfiddle.net/EuEHc/
Code:
for (var i=0; i<items.length; i++) {
var listI = items[i];
loopJ: for (var j=0; j<items.length; j++) {
var listJ = items[j];
if (listI === listJ) continue; //Ignore itself
for (var k=listJ.length; k>=0; k--) {
if (listJ[k] !== listI[k]) continue loopJ;
}
// At this point, their values are equal.
items.splice(j, 1);
}
}
A simple sort and filter, function would do the trick.
var items = [
['al', 'bv', 'sd'],
['al', 'cc', 'ab'],
['cv', 'vv', 'sw'],
['al', 'bv', 'sd']
];
var temp = ''
var unique = items.sort().filter(r => {
if (r.join("") !== temp) {
temp = r.join("")
return true
}
})
console.log(unique);
An unconventional but easier to code version
var items = [['al','bv','sd'],
['al','cc','ab'],
['cv','vv','sw'],
['al','bv','sd']
];
var temp = {};
for ( var i in items ) {
var serialized = JSON.stringify(items[i]);
if ( temp[serialized] ) {
items.splice( i, 1 );
continue;
}
temp[serialized] = true;
}
Try it here! http://jsfiddle.net/y3ccJ/1/
More conventional option:
var items = [['al','bv','sd'],
['al','cc','ab'],
['cv','vv','sw'],
['al','bv','sd']
];
var results = [];
loop: for ( var i in items ) {
compare: for ( var j in results ) {
for ( var k in items[i] ) {
if ( items[i][k] !== results[j][k] ) {
break compare;
}
}
continue loop;
}
results.push( items[i] );
}
http://jsfiddle.net/xhrd6/
If you can use lodash, this is good solution (note that based on your platform, the "require" keyword can differ, this is how to use it in Node.js):
var _ = require('lodash');
var objects = [['a', 'b', 'c'],['a'],['b', 'a', 'c']];
objects.forEach(innerArr => {
innerArr.sort();
});
console.log(_.uniqWith(objects, _.isEqual));
This would be output
[ [ 'a', 'b', 'c' ], [ 'a' ] ]
If order of elements in array matter to you, i.e. this array [ 'a', 'b', 'c' ] is considered different than this one ['b', 'a', 'c'], all you need is to delete the "sort" part :
var _ = require('lodash');
var objects = [['a', 'b', 'c'],['a'],['b', 'a', 'c'], ['a','b','c']];
console.log(_.uniqWith(objects, _.isEqual));
This would be output :
[ [ 'a', 'b', 'c' ], [ 'a' ], [ 'b', 'a', 'c' ] ]
You can do something like this :
var result = [];
result.push(items[0]);
for (i = 1; i < items.length; i++){
var ok;
for (j = 0; j < i; j++){
if (result[j].length != items[i].lenght) continue;
ok = false;
for (k = 0; k < items[i].length; k++) if (items[i][k] != result[j][k]) ok = true;
if (ok == false) break;
}
if (ok) result.push(items[i]);
}
return result;
function arrays_equal(a,b) { return !!a && !!b && !(a<b || b<a); }
Array.prototype.unique = function() {
var a = [];
for (var i = 0, l = this.length; i<l; i++) {
for (var j = i + 1; j < l; j++) if (arrays_equal(this[i], this[j])) j = ++i;
a.push(this[i]);
}
return a;
};
var ret = items.unique();
The demo.
Since this sounds like some sort of school assignment I will provide ideas not code. You should think about how a human looks through that 2D array and determines whether or not one of the arrays is unique or not. One has to look at each other row, for each row to determine if it is unique. Sounds like nested for loop to me ....

Categories

Resources