How to find the match case using for loop in array - javascript

I have two arrays
var arr1 = [
{'id':'1','name':'test1','value':'star','role':['monitor']},
{'id':'2','name':'test2','value':'player','role':['monitor','Supervisor']},
{'id':'3','name':'test3','value':'saviour','role':['Supervisor']},
{'id':'4','name':'test4','value':'rock','role':['monitor']},
{'id':'5','name':'test5','value':'rocky','role':['boxer','monitor']}
]
var arr2 = ['Supervisor','monitor'];
I want to get the result where arr2 values is properly matched with arr1 roles values
Persons having both the category should be pushed to arr3.
So result should be {'id':'2','name':'test2','value':'player','role':['monitor','Supervisor']}.
if arr2 has one value then we can use arr1.indexOf(arr2[0])!='-1' but how to satisfy the "and" condition in the for loop..
I don't want to use this if possible, but it's all I can think of:
if( arr1.indexOf(arr2[0])!='-1' && arr1.indexOf(arr2[1])!='-1'){
return arr1[i];
}

Like #Marc B and #Terry say, you have just to do an intersection.
Here's a version without Jquery :
function intersection(a, b)
{
var result = [], ai = 0, bi = 0;
a.sort();
b.sort();
while( a.length > ai && b.length > bi )
{
if(a[ai] < b[bi] ){
ai++;
}
else if(a[ai] > b[bi] ){
bi++;
}
else
{
result.push(a[ai]);
ai++;
bi++;
}
}
return result;
}
var arr1 = [
{'id':'1','name':'test1','value':'star','role':['monitor']},
{'id':'2','name':'test2','value':'player','role':['monitor','Supervisor']},
{'id':'3','name':'test3','value':'saviour','role':['Supervisor']},
{'id':'4','name':'test4','value':'rock','role':['monitor']},
{'id':'5','name':'test5','value':'rocky','role':['boxer','monitor']}
]
var arr2 = ['Supervisor','monitor'];
var arr3 = [];
arr1.forEach(function(value){
if(intersection(value.role, arr2).length === arr2.length){
arr3.push(value);
}
});
console.log(arr3);

The main trick here is the equality of the arrays.
// Assuming we have array 'equals' method which compares the array equality
// el['role'] == arr2 won't work
var result = arr1.filter(function(el){
return el['role'].equals(arr2);
});
So, we can see that we only have to deal with array equality.
This post How to compare arrays in JavaScript? has a lot of discussion about it. Someone has even implemented 'equals' method.

You can use a jQuery one-liner to compare array—and the best thing is that they don't have to be in the exact same order. Simply use the .not() method, previously mentioned before.
The only trick is to use $.each() to loop through your first array, and compare the array of the role object against arr2 using .not():
var arr1 = [
{'id':'1','name':'test1','value':'star','role':['monitor']},
{'id':'2','name':'test2','value':'player','role':['monitor','Supervisor']},
{'id':'3','name':'test3','value':'saviour','role':['Supervisor']},
{'id':'4','name':'test4','value':'rock','role':['monitor']},
{'id':'5','name':'test5','value':'rocky','role':['boxer','monitor']}
]
var arr2 = ['Supervisor','monitor'];
var arr3 = [];
$.each(arr1, function(idx,person){
if($(person.role).not(arr2).length === 0 && $(arr2).not(person.role).length === 0) {
arr3.push(person);
}
});
console.log(arr3);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Related

What does a[arr1[i]]=true do?

I am a JavaScript beginner. I have previously worked in other programming languages (C, C++ etc). What is the statement a[arr1[i]]=true; doing?
function diff(arr1, arr2) {
var newArr = [];
// Same, same; but different.
var a=[];
for(var i=0;i<arr1.length;i++)
a[arr1[i]]=true;
for(var j=0;j<arr2.length;j++)
if(a[arr2[j]])
delete a[arr2[j]];
else
a[arr2[j]]=true;
for(var k in a)
newArr.push(k);
return newArr;
}
It seems that a is a list of booleans, so that particular assignment sets one of a's indices to true. That index is computed by dereferencing arr1.
In a comment above you expressed a worry to the effect that an array is used as an index inside another array. But no need to worry about that, because it's not the array itself (viz. arr1) that's used as an index, but an element of that array (viz. arr1[i], for some i).
You're wondering about the syntax a[arr1[i]]. It's simple:
arr1[i] value is an index for array a.
If arr1[i] value is a number, 5 as an example. So it will be: a[5]=true. Nothing's special in this case.
As you said in the comment, arr1[i] might be a string, "boy" for example. Then, it will be: a["boy"]=true.
You should know that array index in JavaScript could be a string. But be careful, as W3School said, if you use a named index, JavaScript will redefine the array to a standard object. After that, all array methods and properties will produce incorrect results. For example:
var person = [];
person["firstName"] = "John";
person["lastName"] = "Doe";
person["age"] = 46;
var x = person.length; // person.length will return 0
var y = person[0]; // person[0] will return undefined
For more detail, take a look at the warning part in W3School about this.
Here's your code with comments explaining what's going on and sample output
var arr1 = [1,2,'foo','bar'];
var arr2 = [2,3,'foo'];
var diff = diff(arr1, arr2);
console.log( diff ); // ["1", "3", "bar"]
function diff(arr1, arr2) {
var newArr = [];
var a=[];
// Loop through arr1
// set the value of each entry as an index in array `a`
// set the value of the entry in `a` to true
for(var i=0;i<arr1.length;i++)
a[arr1[i]]=true;
// console.log(a); // [1: true, 2: true, foo: true, bar: true]
// Loop through arr2
// check if each entry exists as an index in array `a`
// if it does, delete the value from array `a`
// if not, set the value of the entry in `a` to true
for(var j=0;j<arr2.length;j++)
if(a[arr2[j]])
delete a[arr2[j]];
else
a[arr2[j]]=true;
// console.log(a); // [1: true, 3: true, bar: true]
// put all of the indexs of array `a` to values in `newArr`
for(var k in a)
newArr.push(k);
return newArr;
}
http://jsfiddle.net/daCrosby/6rcf1j72/
From a code-cleanup side, If you want a shorter function you could use something like one of these:
console.log( "Looping", diffLoop ); // [1, "bar", 3]
console.log( "Filtering", diffFilter ); // [1, "bar", 3]
function diffLoop(arr1, arr2){
var arr = arr1;
for(var j=0; j<arr2.length; j++)
if( arr.indexOf( arr2[j] ) > -1 )
arr.splice(arr.indexOf( arr2[j] ), 1);
else
arr.push(arr2[j]);
return arr;
}
function diffFilter(arr1, arr2){
var arr = arr1.concat(arr2);
return arr.filter(function(i) {
var in1 = arr1.indexOf(i) < 0;
var in2 = arr2.indexOf(i) < 0;
return (in1 || in2) && !(in1 && in2);
});
}
http://jsfiddle.net/daCrosby/6rcf1j72/1/
Same logic as in high level languages applies here as well.
This can easily be clarified splitting this to small blocks.
a[arr1[i]]=true;
arr1 - An array of integer
a - An array of boolean

recursively putting array elements in their own array

I'm trying to create a function that puts each array element in its own array, recursively.
I think my base case is correct, but my recursive call doesn't appear to be working. any insight?
function ownList(arr){
if (arr.length === 1) {
arr[0] = [arr[0]];
return;
} else {
return arr[0].concat(ownList(arr.slice(1)));
}
}
var arr = [1,2,3]
console.log(ownList(arr))// returns []
//should return [[1],[2],[3]]
Here I'm trying to put each pair in it's own list (recursive only). This code below is correct (update)
function ownListPair(arr){
if (arr.length === 0)
return arr;
else if(arr.length === 1)
return [[arr[0], 0]];
else
return [[arr[0], arr[1]]].concat(ownListPair(arr.slice(2)));
}
// var arr = [3,6,8,1,5]
var arr = [2,7,8,3,1,4]
//returns [ [ 2, 7 ], [ 8, 3 ], [ 1, 4 ]]
console.log(ownListPair(arr))
I prefer this solution for several reasons:
function ownList(a) {
return a.length == 0
? []
: [[a[0]]].concat(ownList(a.slice(1)))
}
It's shorter and more concise
It works for empty arrays as well
The actual wrapping happens only once in the last line. Treating length == 1 separately -- as suggested by others -- is not necessary.
It would more appropriate to make a length of 0 be the null case. Then you just have to get the brackets right. The thing on the left side of the concat should be an array consisting of the array containing the first element.
function ownList(arr) {
return arr.length ? [[arr[0]]].concat(ownList(arr.slice(1))) : [];
}
Here's an alternative, take your pick:
function ownList(arr) {
return arr.length ? [[arr.shift()]] . concat(ownList(arr)) : [];
}
Using a bit of ES6 magic for readability:
function ownList([head, ...tail]) {
return head === undefined ? [] : [[head]] . concat(ownList(tail));
}
Here the [head, ...tail] is using parameter destructuring which pulls the argument apart into its first element (head) and an array of remaining ones (tail).
Instead of concat you could also use the array constructor:
function ownList([head, ...tail]) {
return head === undefined ? [] : Array([head], ...ownList(tail));
}
I think your basic assumption is wrong. What you need to do is check if each item in the array is an array, if not just add the item to the new array, if so have the function run itself on the array item.
That is recursion.
This code does that kind of recursion...
function ownList(arr)
{
var newArr = [];
var length = arr.length;
for (var i = 0; i < length; i++) {
if (typeof(arr[i]) === 'object') {
newArr.push(ownList(arr[i]));
continue;
}
newArr.push([arr[i]]);
}
return newArr;
}
var arr = [1, 2, 3];
console.log(ownList(arr));
Would something like this work:
var arr = [1, 2, 3, ["a", "b", "c", ["str"]]],
result = [];
function flatten(input){
input.forEach(function(el){
if(Array.isArray(el)){
flatten(el)
}else{
result.push([el]);
}
});
}
flatten(arr);
console.log(JSON.stringify(result));
//[[1],[2],[3],["a"],["b"],["c"],["str"]]
JSBIN
Edit:
var result = [];
function flatten(input){
if (input.length === 0){
console.log( "result", result ); //[[1],[2],[3],["a"],["b"],["c"],["str"]]
return;
}
//if zeroth el of input !array, push to result
if (!Array.isArray(input[0])){
result.push(input.splice(0, 1));
flatten(input);
}else{
flatten(input[0]); //else, give input[0] back to flatten
}
}
window.onload = function(){
var arr = [1, 2, 3, ["a", "b", "c", ["str"]]];
flatten(arr);
}
JSBIN
After struggling through this today, turns out that this works :)
function ownList(arr){
//base case:
if (arr.length === 1) {
return [arr];
}
//recurse
//have to do two brackets here --> (arr.slice(0,1)) since length > 1
return [arr.slice(0,1)].concat(ownList(arr.slice(1)));
}
var arr = [1,2,3]
console.log(ownList(arr))// returns [[1],[2],[3]]

Removing items from array based on another array

I have two arrays:
var firstArr = [1,2,3,4,5];
var secondArr = [2,3];
How can I get an array like this:
[1,4,5]
I would like to use a solution that could be used when elements of the array are objects with multiple properties.
Use filter:
The filter() method creates a new array with all elements that pass
the test implemented by the provided function.
For example:
firstArr.filter(function(item){
return secondArr.indexOf(item) === -1;
});
You can use this Function to remove items.
function removeA(arr) {
var what, a = arguments, L = a.length, ax;
while (L > 1 && arr.length) {
what = a[--L];
while ((ax= arr.indexOf(what)) !== -1) {
arr.splice(ax, 1);
}
}
return arr;
}
var ary = ['three', 'seven', 'eleven'];
removeA(ary, 'seven');

Finding nested duplicate arrays in JavaScript. (Nested Array uniq in lodash/underscore)

I am trying to determine if an array of JavaScript arrays contains duplicates. Is this possible? I am first trying to see if I can strip the duplicates out and then do an equality check but I cannot get past the first part. Here is what underscore returns:
var arr1 = [[1,2], [2,3], [1,2]];
var arr2 = _.uniq(arr1);
var arraysAreEqual = _.isEqual(arr1, arr2);
console.log(arraysAreEqual, arr1, arr2);
// true
Jsbin: http://jsbin.com/vogumo/1/edit?js,console
Anyone know of a way to determine if the array contains duplicate arrays?
It's a little sloppy, but (possible)
var arr2 = _.uniq(arr1, function(item) {
return JSON.stringify(item);
});
will give you a correct result
Try This:
var numArray = [1, 7, 3, 0, 9, 7, 8, 6, 2, 3];
var duplicates = [];
var sortednumArray = numArray.sort();
for (var i = 0; i < sortednumArray.length; i++) {
//console.log(sortednumArray[i]);
if (sortednumArray[i] == sortednumArray[i + 1]) {
duplicates.push(sortednumArray[i]);
}
}
if (duplicates.length == 0) {
console.log("Soted Array:");
for(var i = 0; i < sortednumArray.length; i++) {
console.log(sortednumArray[i]);
}
} else {
console.log("Duplicates:");
for(var i = 0; i < duplicates.length; i++){
console.log(duplicates[i]);
}
}
Program pushes all duplicates to an array called 'duplicates' then displays it, but if none are present, it displays the sorted version of numArray
From the underscore.js documentation:
uniq _.uniq(array, [isSorted], [iteratee]) Alias: unique
Produces a
duplicate-free version of the array, using === to test object
equality. If you know in advance that the array is sorted, passing
true for isSorted will run a much faster algorithm. If you want to
compute unique items based on a transformation, pass an iteratee
function.
But arrays can't be strictly compared in JavaScript.
Therefore, you can use a transformation function to enable comparison with uniq. For example:
console.log([1,2] === [1,2]) // false, can't strict compare arrays
console.log([1,2].toString()) // "1,2" - string representation
console.log([1,2].toString() === [1,2].toString()) // true, strings can be compared
var valueToString = function(v) {return v.toString()}; // transform array to string
var arr1 = [[1,2], [2,3], [1,2]];
var arr2 = _.uniq(arr1, false, valueToString); // compare based on transformation
var arraysAreEqual = _.isEqual(arr1, arr2);
console.log("arraysAreEqual:", arraysAreEqual, arr1, arr2);
// false
// [[1, 2], [2, 3], [1, 2]]
// [[1, 2], [2, 3]]
Note that transforming to string is "hacky": you would be better off comparing each value of the array, as discussed in this StackOverflow question.
By using the proposed equals implementation in that question, you would need to implement your own version of uniq that uses equals instead of ===.
The implementation of uniq in Underscore is very straight-forward - it creates a new result array and loops through the given array. If the current value is not already in result, insert it.
console.log("Using array comparison:");
arrayEquals = function (array1, array2) {
// if any array is a falsy value, return
if (!array1 || !array2)
return false;
// compare lengths - can save a lot of time
if (array1.length != array2.length)
return false;
for (var i = 0, l=array1.length; i < l; i++) {
// Check if we have nested arrays
if (array1[i] instanceof Array && array2[i] instanceof Array) {
// recurse into the nested arrays
if (!arrayEquals(array1[i],array2[i]))
return false;
}
else if (array1[i] !== array2[i]) {
return false;
}
}
return true;
};
_.uniqArrays = function(array) {
if (array == null) return [];
var result = [];
for (var i = 0, length = array.length; i < length; i++) {
var value = array[i];
var arrayEqualsToValue = arrayEquals.bind(this, value); // arrayEquals with first argument set to value
var existing = _.find(result, arrayEqualsToValue); // did we already find this?
if (!existing) {
result.push(value);
}
}
return result;
};
var arr3 = _.uniqArrays(arr1);
arraysAreEqual = _.isEqual(arr1, arr3);
console.log("arraysAreEqual:", arraysAreEqual, arr1, arr3); // false
I made a jsbin with all the code, if you want to play around.
In the latest lodash (4.6.1) you could do something like this:
if (_.uniqWith(arr, _.isEqual).length < arr.length) {
// then there were duplicates
}

Using Javascript to sort an array of numeric arrays

In Javascript, if I have an array of arrays, like the following:
X = [ [1,2,3,4],
[1,1,2,3],
[1,1,3],
[1,4],
[2,1,2],
[2,2]
]
Javascript sorts my array, comparing first entry first, then second, and so on, so that X.sort() returns the following:
[ [1,1,2,3],
[1,1,3],
[1,2,3,4],
[1,4],
[2,1,2],
[2,2]
]
Which is what I want. The problem is that the comparison operator for comparing the elements in the arrays is lexicographical, so [10,2] < [2,2], and, for example,
[[10,2],[1,1,3],[2,2]].sort() -> [[1,1,3],[10,2],[2,2]]
I need it to sort numerically, so that I get a sorted array of [[1,1,3],[2,2],[10,2]].
I tried using a comparison function of function(a,b){return (a-b) }, which would work for sorting an array of numbers, but this fails to properly sort my array, which makes sense (I think) because [10,2] - [1,1,3] yields NaN
How do I go about sorting an array of numeric arrays?
As I said in my comment, the sort function needs to account for the fact that it's receiving arrays as arguments and not plain values. So you need to handle them accordingly.
I suggest this;
var compFunc = function (a, b) {
var len = a.length > b.length ? b.length : a.length;
for(var i=0; i<len; ++i) {
if(a[i] - b[i] !== 0)
return a[i] - b[i];
}
return (a.length - b.length);
};
It first tries to look for differences in the common length of the two arrays. If the common length is exactly the same, then it sorts on the basis of array length. Here's a working fiddle.
What you want is to run a natural sort. For your compare function, replace it with the script mentioned in this article
http://my.opera.com/GreyWyvern/blog/show.dml/1671288
When you do X.sort(), Javascript is comparing your individual arrays as strings. It's basically doing a.toString().localeCompare(b.toString()). This is not what you want.
a.toString() is usually the same as a.join(',')
What I would do is compare each element in the arrays by using a for loop.
Something like this:
X.sort(function(a,b){
// Start off assuming values are equal
var ret = 0;
// Loop through a
for(var a_i = 0, a_length = a.length; a_i < a_length; a_i++){
// If b is shorter than a, it comes first
if(typeof b[a_i] === 'undefined'){
ret = 1;
break;
}
// if the element in a and b are *not* the same, then we can sort
else if(a[a_i] !== b[a_i]){
ret = a[a_i] - b[a_i];
break;
}
}
return ret;
});
You need to sort and compare between the 2 arrays:
http://jsfiddle.net/pXzB6/
var arr = [[10,2],[1,1,3],[2,2]];
arr.sort(function(a,b){
for(var i=0;i<a.length;i++){
var item_a = a[i];
for(var j=0;j<b.length;b++){
var item_b = b[j];
if(item_a == item_b){
continue;
}
else{
return item_a > item_b;
}
}
}
if(a.length == b.length){
return 0;
}
else{
return a.length > b.length;
}
});
console.log(arr);
var points = [40, 100, 1, 5, 25, 10];
points.sort(function(a, b){return a-b});
then the result is :
1,5,10,25,40,100
This is simplest way i think, it's worked.

Categories