Comparing Arrays - javascript

I have a little piece of code where an array is populated with arrays. At the end, I have this array with n member arrays. These sub-arrays always have the same number of members (2) of the same type (number). I need to know if these sub-arrays are all identical (same members, same position). This always returns false:
[2, 0] === [2, 0]
Off the top of my head, I can think of two ways to compare.
A loop in which I test (member[i][0] === member[i+1][0] && member[i][1] === member[i+1][1]).
The same loop, with this test: (member[i].toString() === member[i + 1].toString()).
I think I'm taking this the wrong way. What do you think?

FOR MY OWN THINKING, I think it is correct to use the loop to compare two array.
var isTheSame = true;
for (var i in array1) {
if (array1[i] !== array2[i]) isTheSame = false;
}
The loop above works, it will return false either any of the element different from type (three equal sign ===), or value, or length or even key.
The second suggestion of you should not work as exactly as the first one, because you convert it into a string already, what happen if array1[0] = "true" and array2[0] = true? It will return true, because now all of them are string, but you need the exact comparison right?
That's my own thinking, I hope it might help somehow.
Regards,
[x]

a=[2,0]; b=[2,0]; a.toString() == b.toString();
perhaps not the most efficient, but it seems to work, and I'm a strong proponent of the shorter and more readable solution.
note that xx3004's point about the type data lost when converting to string is something to think about, unless you know for sure that your arrays will be composed of the same data types.

You can use the below to get true or false on whether two one-dimensional arrays are identical. It needs to be recursive if you add dimensions, but this will suffice for what you're asking, I think.
function testArray(a, b) {
var aLen = a.length;
var bLen = b.length;
if (aLen === bLen) { // check for identical length first
for (var i = 0; i < aLen; i++) {
if (a[i] !== b[i]) {
return false; // members don't match
}
}
return true; // all members matched
}
return false; // not same length
}
http://jsfiddle.net/pgkUr/

This is what I came up with...
var arrayCompare = function(a, b) {
var aLength = a.length,
bLength = b.length;
if (aLength != bLength) {
return false;
}
for (var i = 0; i < aLength; i++) {
if (a[i] !== b[i]) {
return false;
}
}
return true;
}

Here's an easy way to compare the two arrays, building on your toString idea (even multidimensional ones will work):
function compareArrays(a1, a2) {
return JSON.stringify(a1) == JSON.stringify(a2);
}
compareArrays([[2,3],[7,4],[3,3]], [[2,3],[7,4],[3,3]]) // true
compareArrays([[2,3],[7,4],[3,3]], [[7,4],[2,3],[3,3]]) // false

If your willing to use Underscore, which is simply great tool (I value it as much or even higher than jQuery), you could simplify this code quite a lot. You don't need nesting during comparing arrays: I would flatten them beforehand. Then it's just one loop:
function cmpArrays( arr1, arr2 ){
var flat = _.zip( _.flatten( arr1 ), _.flatten( arr2 ) );
for( var elem in flat ){
if( flat[elem][0] !== flat[elem][1] ){
return false;
}
}
return true;
}
generalizing this to work with any number of arrays should be very simple as well.

Related

Am I using sort() wrong?

I was doing a little coding challenge, and it was to write a function that would return true if the arr parameter, which was an array of number, was sorted in ascending order. I can't seem to figure this out, but my code, no matter what, always returns true.
function inAscOrder(arr) {
return arr.sort() === arr;
}
As others have pointed out, a major issue with your version is that it uses the mutating sort. Although you could fix this by inserting a slice(0) or some such to clone the array, and then writing an index-by-index equality tester, it's much easier to simply test if each successive entry is larger than the previous one.
Perhaps the most elegant way to do that is through recursion. Here's one example:
const inAscOrder = (a) => a.length < 2 || (a[0] < a[1] && inAscOrder(a.slice(1)))
This might not be workable for larger arrays because of Javascript's recursion depth limits. But an iterative version of the same thing is fairly straightforward:
const inAscOrder = (a) => {
if (a.length < 2) {return true}
for (let i = 1; i < a.length; i++) {
if (a[i -1] > a[i]) {return false}
}
return true
}
You do not need to sort the array to see if it is sorted. Just you need to check whether it is sorted or not.
static boolean arraySortedOrNot(int arr[], int n)
{
// Array has one or no element
if (n == 0 || n == 1)
return true;
for (int i = 1; i < n; i++)
// Unsorted pair found
if (arr[i-1] > arr[i])
return false;
// No unsorted pair found
return true;
}
reference link:
https://www.geeksforgeeks.org/program-check-array-sorted-not-iterative-recursive/
Since array is a mutable datatype, your arr will get modified when you call the sort method on it.
So arr.sort() will modify your array instead of just returning a sorted array. So thats why when u check again if its equal to arr, it will be the same sorted array.
To overcome this I suggest you copy the arr to some another array and sort that and test it.

How can I find the index of an element, in an array of arrays?

Here is a simple example of an array that contains at least one other array. I want a way to find the index of an array, within an array. However, the code I have below does not work:
var arr = [1,2,[1,2]];
console.log(arr.indexOf([1,2])); //-> -1
for (var i = 0; i < arr.length; i++) {
if (arr[i] == [1,2])
return 'true' // does not return true
}
Intuitively, this should work but does not:
if ([1,2] == [1,2]) return 'true' // does not return true
Can someone explain why it does not work, and offer an alternative solution? Thanks!
No, but you can check it yourself:
var a = [1,2], b = [1,2];
a.length === b.length && a.every(function(x,y) { return x === b[y]; });
Arrays in JavaScript are compared by reference not by value. That is why
console.log([1,2] == [1,2])
returns false.
You need a custom function that could compare arrays. If you want to check only the first level of nesting you can use this code:
var compareArrays = function(a, b) {
if (a.length !== b.length) {
return false;
}
for (var i = 0, len = a.length; i < len; i++) {
if (a[i] !== b[i]) {
return false;
}
}
return true;
}
You are confusing the definitions of similar objects vs. the same object. Array.prototype.indexOf() compares the objects using the strict equality comparison algorithm. For (many) objects, this means an object reference comparison (i.e. the object's unique identifier, almost like its memory address).
In your example above, you are trying to treat two similar arrays as though they were the same array, and that's why it doesn't work. To do what you are trying to do, you need to use the same array. Like this:
var testArr = [1,2]; //a specific object with a specific reference
var arr = [1,2,testArr]; //the same array, not a different but similar array
console.log(arr.indexOf(testArr)); //returns 2
If you just want to know where arrays occur in the parent array, use Array.isArray():
...
if(Array.isArray(arr[i])) {
//do something
}
...
Hopefully that helps!

Determining whether an array contains duplicate values

I would like to scan through a JS array and determine if all the elements are unique, or whether the array contains duplicates.
example :
my_array1 = [1, 2, 3]
my_array2 = [1, 1, 1]
I want get result like this :
my_array1 must be return true, because this array element is unique
and array2 must be return false, because this array element is not unique
How can I go about writing this method?
Sort your array first of all, and then go for a simple comparison loop.
function checkIfArrayIsUnique(arr) {
var myArray = arr.sort();
for (var i = 0; i < myArray.length; i++) {
if (myArray.indexOf(myArray[i]) !== myArray.lastIndexOf(myArray[i])) {
return false;
}
}
return true;
}
if you want to check for uniqueness you can also do this.As stated on the comment i do not assert this is as the only best option.There are some great answers down below.
var arr = [2,3,4,6,7,8,9];
var uniq = []; // we will use this to store the unique numbers found
// in the process for doing the comparison
var result = arr.slice(0).every(function(item, index, array){
if(uniq.indexOf(item) > -1){
// short circuit the loop
array.length=0; //(B)
return false;
}else{
uniq.push(item);
return true;
}
});
result --> true
arr.slice(0) creates a temporary copy of the array, on which the actual processing is done.This is because when the uniqueness criteria is met i clear the array (B) to short circuit the loop.This will make sure the processing stops as soon as the criteria is met.
And will be more nicer if we expose this as a method on a Array instance.
so we can do something like this [1,2,3,5,7].isUnique();
Add the following snippet and you are ready to go
Array.prototype.isUnique = function() {
var uniq = [];
var result = this.slice(0).every(function(item, index, arr) {
if (uniq.indexOf(item) > -1) {
arr.length = 0;
return false;
} else {
uniq.push(item);
return true;
}
});
return result;
};
arr.isUnique() --> true
DEMO
You may try like this:
function uniqueArray(arr) {
var hash = {}, result = [];
for ( var i = 0, l = arr.length; i < l; ++i ) {
if ( !hash.hasOwnProperty(arr[i]) ) {
hash[ arr[i] ] = true;
result.push(arr[i]);
}
}
return result;
}
try this :-
var my_array1 = [1, 2, 3]
var my_array2 = [1, 1, 1]
function isUnique(obj)
{
var unique=obj.filter(function(itm,i,a){
return i==a.indexOf(itm);
});
return unique.length == obj.length;
}
alert(isUnique(my_array1))
alert(isUnique(my_array2))
Demo
I think you can try with Underscore js , a powerful javascript library
Example the way to use underscore
function checkUniqueArr(arr){
var unique_arr = _.uniq(arr);
return arr.length == unique_arr.length;
}
The most efficient way to test uniqueness is:
function isUnique(arr) {
for(var i = 0; i < arr.length; i++) {
if (arr.indexOf(arr[i]) != i) return false;
}
return true;
}
This is O(n2) at worst case. At most time, it doesn't need to finish scanning for not-unique array.
function containsDuplicates(arr) {
var seen = {};
var duplicate = false;
for (var i = 0; i < arr.length; i++) {
if (seen[arr[i]]) {
duplicate = true;
break;
}
seen[arr[i]] = true;
}
return duplicate;
}
jsFiddle
Best-case: O(1) time and space - second element is the duplicate
Average/worst-case: O(n) time and space - no duplicates, or the duplicate is in the middle
Many of the answers here seem to be relying on some complex interspersion of array methods, which are inherently iterative, and generally don't seem appropriate for this fairly simple task. Algorithmically, this problem can be solved in O(n) time, but any nesting of indexOf/filter/map (or similar array methods) in a for loop means that your computation time will grow (at best) quadratically with your array size, rather than linearly. This is inefficient in time.
Now, in general, micro-optimization really is not necessary unless you have identified this to be a performance bottleneck in your application. But this kind of algorithm, in my opinion, is something you design (in pseudocode) and match to your application's needs before you even start coding. If you will have a huge data-set in your array, you will probably appreciate not having to look through it several times to get your answer. Of course, the caveat here is that you're trading time complexity for space complexity, since my solution requires O(n) space for caching previously seen values.
If you need to check all element are unique then following will do the trick
<script>
my_array1 = [11, 20, 3]
my_array2 = [11, 11, 11]
var sorted1= my_array1.sort();
var sorted2= my_array2.sort();
if(sorted1[0]==sorted1[sorted1.length-1])
alert('all same');
if(sorted2[0]==sorted2[sorted2.length-1])
alert('all same');
</script>
I just came up with this answer.
I'm preparing for an interview.
I think this is rock solid.
let r = [1,9,2,3,8];
let r2 = [9,3,6,3,8];
let isThereDuplicates= r.slice().sort().some((item,index,ar)=>(item ===ar[index+1]));
console.log('r is: ',isThereDuplicates) // -> false. All numbers are unique
isThereDuplicates= r2.slice().sort().some((item,index,ar)=>(item ===ar[index+1]));
console.log('r2 is: ',isThereDuplicates) //->true. 3 is duplicated
I first slice and sort without mutating the original array.
r.slice().sort()
Then I check that for at least one item, item is equal to the next item on the array.
.some((item,index,array)=>
item === array[index+1]
);

Selectively push items to an array

So if I had:
A=['a','b','c'];
B=[];
for (var i = 0;i<7;i++){
B.push(A[i])
}
I would get
B=["a", "b", "c", undefined, undefined, undefined, undefined]
Instead I want
B= ["a","b","c"]
So I guess I would need something like
for (var i = 0;i<7;i++){
B.push(A[i] "unless A[i] is undefined. Then don't push anything")
}
How would I do this in Javascript?
Some ES magic
[1, 2, undefined].filter(Boolean)
will produce
[1, 2]
I think this is what you're searching:
Array#filter
B = A.filter(function (element) {
return element !== undefined;
});
That Code will make a duplicate of A filtering out all undefined elements.
Instead of iterating the array and pushing elements one at a time to a new array, it's usually more efficient to use the Array.filter function, like so:
var B = A.filter(function(item){ return item !== undefined; });
You may also want to be cautious about using undefined. This is easily confused with other constructs such as null or empty strings. If you use "!=" instead of "!==" in the function, that will filter out null or missing array items, as well as items which are set specifically as undefined.
You could add a safeguard like
A[i] && B.push(A[i])
which would only push if A1 returns a true, but that would also give false if A[i] would be 0
Example
I would suggest checking against null
if (A[i] != null) B.push(A[i])
Example
If you want to keep your first forloop as it is you can "clean" the array after by using filter. Like:
for (var i = 0; i < 7; i++) {
B.push(A[i])
}
var clean_B = B.filter(function (item) {
return item != null;
});
Example
An Object Oriented Aspect
=> After that code, clean your array :
B.clean();
Known that clean is an extension of array Class(OOP context)
Array.prototype.clean=function(){
var newArray = [];
for(var index = 0; index < this.length; index++) {
if(this[index]) {
newArray.push(this[index]);
}
}
return newArray;
};
You stated the answer to your question in your sort-of comment (use // at the end of the line next time, no need for inserting a comment in a string).
unless A[i] is undefined. Then don't push anything
Another way of putting it is, if A[i] is not undefined, then push.
When put like that, it directly translates into code.
if (A[i] !== undefined)
{
B.push(A[i]);
}
I elaborated on your comment to show you how easily you can figure these types of questions out with a little effort and time.
However, as others have stated, a much better way of ignoring undefined indices is to simply iterate to A.length, however this only works if there are no undefined values in-between the defined values (which is still likely the case).
Your problem would be solved by iterating from 1 to array.length, or by using a for in loop
If you're going to be dealing with arrays that could have undefined elements, for example [0, undefined, 4], then you'd need to check if the element is defined before you add it. if(a[i] !== undefined) will do the trick.
You would use an if statement
for (var i = 0; i < 7; i++){
if (A[i] !== undefined) {
B.push(A[i]);
}
}
You can have a compact function to filter out undefined values:
function compact(col) {
return col.filter(function(val) {
return val !== undefined;
});
}
console.log(compact([false,0,1,null,undefined])); // [false,0,1,null]
JS Bin Example
http://jsbin.com/mabowana/4/edit
initials:
A = ['a', 'b', 'c'];
B = [];
I think, the closest answer to OP's question would be this:
for (var i = 0; i < 7; i++) {
if (typeof A[i] !== "undefined") B.push(A[i]);
else continue;
}
or this one:
for (elem of A) if (typeof elem !== "undefined") B.push(elem); else continue;
Instead of hard coding i < 7, use i < A.length
for (var i = 0; i < A.length; i++){
B.push(A[i])
}

inArray, indexOf in a 2-dimensional array

i have an 2-dimensional array. for example
var bruecken = [[1,2],[3,4]];
now i am trying to test, if a subarray exists:
console.log(jQuery.inArray([1,2], bruecken));
or
console.log(bruecken.indexOf([1,2]));
but both ways it returns -1. what am i doing wrong?
The fastest way would be to use a for loop and compare them, then return if found. Here is something you can work with, I used JSON for comparison, but you can just use whatever comparator you find best (there are plenty):
function arrayInArray(needle, haystack) {
var i=0, len=haystack.length, target=JSON.stringify(needle);
for(; i<len; i++) {
if (JSON.stringify(haystack[i]) == target) {
return i;
}
}
return -1;
}
arrayInArray( [0,1], [ [1,2], [0,1] ] ); // 1
If you want booleans, just return true instead of i and false instead of -1.
I don't think inArray will work because comparing two identical arrays using == will return false. You could try using grep instead:
function subArrayInArray(subArray, array){
var matches = $.grep(array, function(a){
// Compare the target array with each of the child arrays
return $(subArray).not(a).length == 0 && $(a).not(subArray).length == 0;
});
return !!matches.length;
}
The method for comparing two arrays was stolen from this question

Categories