I am having trouble checking the contents of an array contained within a main array.
Example:
I have two arrays
var main = [[1,2,3],
[4,5,6]];
var compare = [1,2,4,5,6]
I want to compare the array "compare" with each array within the array "main" to see if it contains any of the numbers. The result would be something I could then test against (boolean or the index position).
I tried indexOf and couldn't figure it out.
Edit
This should still return true:
var main = [[1,2,3], // returns false
[4,5,6], // returns false
[7,8,9], // returns true
[2,3,7]]; // returns true
var compare = [2,3,4,6,7,8,9]
** Update w/ Solution ***
I needed to check if compare array's contents matched any of the subarrays in main. Here's what I came up with:
var main = [[1, 2, 3],
[4,5,6]];
var counter = 0;
var counter2 = 0;
var compare = [4,1,3,2];
for (var i = 0; i <= compare.length; i++) {
// Sorting
compare.sort();
if (main[0].indexOf(compare[i]) > -1) {
counter++;
console.log("Added a point to counter 1");
} else if (main[1].indexOf(compare[i]) > -1) {
counter2++;
console.log("Added a point to counter 2");
} else {
console.log("No points added");
}
}
// if any of the counters have 3 marks, then the player hit it 3 times.
if (counter == 3 || counter2 === 3){
console.log("A counter is at 3");
}
Any feedback on what I came up with? What's a better way of doing this?
You'll need 2 loops, the first to iterate over your array of arrays, the next to check for existing elements within the current array:
for (var i = 0; i < main.length; i++) {
for (var j = 0; j < main[i].length; j++) {
if (compare.indexOf(main[i][j]) {
//compare has a number from the current array! main[i][j] exists in compare!
}
}
}
Take a look at lodash library, the have that exact functionality written already
You can use built-in array methods:
var result = main.map(function(xs) {
return xs.some(function(x) {
return compare.indexOf(x) > -1
})
})
It will return [true, true]
Following, two of the possible solutions:
Suppose:
var main = [[1,2,3],
[4,5,6],
[7,8,9],
[2,3,7],
[5,1,10]];
var compare = [2,3,4,6,7,8,9];
First solution: return true if any element of the main inner array is included in the master one which is compare:
var result1= main.map(function(element,index,array){
return element.reduce(function(previousValue, currentValue, index, array){
return (previousValue || (compare.indexOf(currentValue) >= 0));
}, false);
});
This solution gives the following result:
result1 = [true,true,true,true,false]
Second solution: return the index of the main inner array elements in compare:
var result2= main.map(function(element,index,array){
return element.map(function(element,index,array){
return (compare.indexOf(element));
});
});
This solution gives the following result:
result2 = [[-1,0,1],[2,-1,3],[4,5,6],[0,1,4],[-1,-1,-1]]
Check this link jsfiddle to see a working example.
Hope it's useful!
Related
I would like to cache some data in javascript, but the cache should be limited to 10 elements for example.
I can place the objects in javascript array, but what is the best way to keep the array limited to 10 elements?
Example:
function getData(dataId) { return new NextDataObject(dataId); }
var array = new Array();
array.push(getData(0));
array.push(getData(1));
(...)
array.push(getData(10)); // this should result in dropping "oldest" data, so getData(0) should be removed from the array, so that in array there are only 10 objects at maximum
Should such mechanism be written manually (using splice() for example?) or are there better ways to achieve such "cache" structure in javascript?
BTW: in this particular situation I'm using angular.
Override the push function of your caching array.
var array = new Array()
array.push = function (){
if (this.length >= 10) {
this.shift();
}
return Array.prototype.push.apply(this,arguments);
}
Plunker
To make this more reusable I created a method which returns new instance of such array (basing on above code).
function getArrayWithLimitedLength(length) {
var array = new Array();
array.push = function () {
if (this.length >= length) {
this.shift();
}
return Array.prototype.push.apply(this,arguments);
}
return array;
}
var array = getArrayWithLimitedLength(10);
To remove first element from array use shift:
if (arr.length > 10) {
arr.shift(); // removes the first element from an array
}
How about this object?
function Cache(maxLength) {
this.values = [];
this.store = function(data) {
if(this.values.length >= maxLength) {
this.getLast();
}
return this.values.push(data);
}
this.getLast = function() {
return this.values.splice(0,1)[0];
}
}
cache = new Cache(3);
// => Cache {values: Array[0]}
cache.store(1)
// => 1
cache.store(2)
// =>2
cache.store(3)
// => 3
cache.store(4)
// =>3
cache.values
// => [2, 3, 4]
cache.getLast()
// => 2
cache.values
[3, 4]
You could create new method in Array.prototype to mimic your needs.
Array.prototype.push_with_limit = function(element, limit){
var limit = limit || 10;
var length = this.length;
if( length == limit ){
this.shift();
}
this.push(element);
}
var arr = []
arr.push_with_limit(4); // [4]
arr.push_with_limit(9); // [4, 9]
....
// 11th element
arr.push_with_limit(3); // [9, ..., 3] 10 elements
Simple fixed length queue:
Array.prototype.qpush = function( vals, fixed ) {
if (arguments.length) {
if (Array.isArray(vals)) {
for (var v of vals) {
this.push(v);
}
} else {
this.push(vals);
}
var _f = (typeof this.fixed != undefined) ? this.fixed : 0;
if (typeof fixed != undefined) {
_f = (Number(fixed)===fixed && fixed%1===0 ) ? fixed : _f;
}
this.fixed = _f;
if (this.fixed>0) this.splice(0, this.length - _f);
}
}
var q = new Array();
q.push(0);
q.qpush( [1, 2, 3], 10 );
q.qpush( [4] );
q.qpush( 5 );
q.qpush( [6, 7, 8, 9, 10, {k:"object"} ] );
console.log(q);
if(array.length == 10) {
array.splice(0, 1);
// this will delete first element in array
}
If you do a check whether the array has reached 10 entries with array.length, just remove the first element before pushing a new element. This can be done several ways as Tushar states, array.shift() would be the fastest, but you can indeed use array.splice() aswell.
It would look like this:
if(array.length > 10) {
array.shift();
array.push(getData(10));
}
On a side note, instead of using var array = new Array() I suggest you simply use var array = [];. This is because the new keyword in Javascript sometimes has bad side effects. If you for example want to create an array with 1 element being a digit, and you use var arr = new Array(12);, an array with 12 undefined elements will be created. Whereas var arr = [12]; will create an array with 1 element, the digit 12.
But I guess that's a minor thing to consider..
You could use an object instead...
var obj = {}; //your cache object
obj[window.performance.now()] = getData(val); //add value, index by microsecond timestamp
if(Object.keys(obj).length > 10){ // then if the length ever gets bigger than 10..
var array = Object.keys(obj).sort(); //sort the properties by microsecond asc
delete obj[array[0]]; //delete the oldest one
}
Here is a jsFiddle example showing how it works: https://jsfiddle.net/uhkvk4mw/
just check if the length is reached then pop it
if(arr.length > someNumber){
arr.pop(); // pop() will remove the last element
}
This question already has answers here:
Get all non-unique values (i.e.: duplicate/more than one occurrence) in an array
(97 answers)
Closed 9 years ago.
Any idea how to get this:
var MyArr = [0,1,2,3,"something",44,661,3,1,"something"]
var Results = [1,3,"something"]
I just want to find duplicated values in my array.
Use a for loop:
var Results = [];
MyArr.forEach(function(el, idx){
//check if value is duplicated
var duplicated = MyArr.indexOf(el, idx + 1) > 0;
if(duplicated && Results.indexOf(el) < 0) {
//duplicated and not in array
Results.push(el);
}
});
Solution with O(n) time and O(n) space. Example:
Results = duplicates(MyArr);
Using map data structure. Works only if there are strings or numbers in MyArr;
function duplicates(input) {
var results = [],
_map = {};
for (var i in input) {
if (typeof _map[input[i]] == "undefined") {
_map[input[i]] = 1;
}
else {
_map[input[i]]++;
}
}
for (var argument in _map) {
if (_map[argument] > 1) {
results.push(argument);
}
}
return results;
}
PS: Because _map[input[i]] takes O(1) time because it is a hash table, but indexOf() takes O(n) time.
PS2: Another solution with lower constant:
function duplicates(input) {
var results = [],
_map = {};
WAS = 1,
SKIP = -1;
for (var i in input) {
if (typeof _map[input[i]] == "undefined") {
_map[input[i]] = WAS;
}
else if (_map[input[i]] == WAS) {
_map[input[i]] = SKIP;
results.push(input[i]);
}
}
return results;
}
You could store each value in a new array, and before adding a new item to such array check if it already exists, and get the results back. Example using Array.forEach():
var myArr = [1,2,3,2];
var results = [];
myArr.forEach(function(item) {
if (results.indexOf(item) < 0) {
results.push(item);
}
});
If you just want the duplicated values, you could use a very similar approach and make use of Array.filter.
Note: beware that Array.indexOf() does not work on IE8, for example, you could use jQuery.inArray() method
You can mimic a counted set by using an object whose properties are elements of the set and whose values are the number of occurrences. So you can convert your array to a counted set and read off the elements that have a count of two or more. (This works only if the elements of MyArr are strings or numbers.)
So try this:
var counts = {} ;
MyArr.forEach(function(el){
counts[el] = counts[el]==undefined ? 1 : counts[el]+1 ;
});
var Results = Object.keys(counts).filter(function(el){
return counts[el] > 1 ;
}) ;
I have an array like this:
[{prop1:"abc",prop2:"qwe"},{prop1:"bnmb",prop2:"yutu"},{prop1:"zxvz",prop2:"qwrq"},...]
How can I get the index of the object that matches a condition, without iterating over the entire array?
For instance, given prop2=="yutu", I want to get index 1.
I saw .indexOf() but think it's used for simple arrays like ["a1","a2",...]. I also checked $.grep() but this returns objects, not the index.
As of 2016, you're supposed to use Array.findIndex (an ES2015/ES6 standard) for this:
a = [
{prop1:"abc",prop2:"qwe"},
{prop1:"bnmb",prop2:"yutu"},
{prop1:"zxvz",prop2:"qwrq"}];
index = a.findIndex(x => x.prop2 ==="yutu");
console.log(index);
It's supported in Google Chrome, Firefox and Edge. For Internet Explorer, there's a polyfill on the linked page.
Performance note
Function calls are expensive, therefore with really big arrays a simple loop will perform much better than findIndex:
let test = [];
for (let i = 0; i < 1e6; i++)
test.push({prop: i});
let search = test.length - 1;
let count = 100;
console.time('findIndex/predefined function');
let fn = obj => obj.prop === search;
for (let i = 0; i < count; i++)
test.findIndex(fn);
console.timeEnd('findIndex/predefined function');
console.time('findIndex/dynamic function');
for (let i = 0; i < count; i++)
test.findIndex(obj => obj.prop === search);
console.timeEnd('findIndex/dynamic function');
console.time('loop');
for (let i = 0; i < count; i++) {
for (let index = 0; index < test.length; index++) {
if (test[index].prop === search) {
break;
}
}
}
console.timeEnd('loop');
As with most optimizations, this should be applied with care and only when actually needed.
How can I get the index of the object tha match a condition (without iterate along the array)?
You cannot, something has to iterate through the array (at least once).
If the condition changes a lot, then you'll have to loop through and look at the objects therein to see if they match the condition. However, on a system with ES5 features (or if you install a shim), that iteration can be done fairly concisely:
var index;
yourArray.some(function(entry, i) {
if (entry.prop2 == "yutu") {
index = i;
return true;
}
});
That uses the new(ish) Array#some function, which loops through the entries in the array until the function you give it returns true. The function I've given it saves the index of the matching entry, then returns true to stop the iteration.
Or of course, just use a for loop. Your various iteration options are covered in this other answer.
But if you're always going to be using the same property for this lookup, and if the property values are unique, you can loop just once and create an object to map them:
var prop2map = {};
yourArray.forEach(function(entry) {
prop2map[entry.prop2] = entry;
});
(Or, again, you could use a for loop or any of your other options.)
Then if you need to find the entry with prop2 = "yutu", you can do this:
var entry = prop2map["yutu"];
I call this "cross-indexing" the array. Naturally, if you remove or add entries (or change their prop2 values), you need to update your mapping object as well.
What TJ Crowder said, everyway will have some kind of hidden iteration, with lodash this becomes:
var index = _.findIndex(array, {prop2: 'yutu'})
var CarId = 23;
//x.VehicleId property to match in the object array
var carIndex = CarsList.map(function (x) { return x.VehicleId; }).indexOf(CarId);
And for basic array numbers you can also do this:
var numberList = [100,200,300,400,500];
var index = numberList.indexOf(200); // 1
You will get -1 if it cannot find a value in the array.
var index;
yourArray.some(function (elem, i) {
return elem.prop2 === 'yutu' ? (index = i, true) : false;
});
Iterate over all elements of array.
It returns either the index and true or false if the condition does not match.
Important is the explicit return value of true (or a value which boolean result is true). The single assignment is not sufficient, because of a possible index with 0 (Boolean(0) === false), which would not result an error but disables the break of the iteration.
Edit
An even shorter version of the above:
yourArray.some(function (elem, i) {
return elem.prop2 === 'yutu' && ~(index = i);
});
Using Array.map() and Array.indexOf(string)
const arr = [{
prop1: "abc",
prop2: "qwe"
}, {
prop1: "bnmb",
prop2: "yutu"
}, {
prop1: "zxvz",
prop2: "qwrq"
}]
const index = arr.map(i => i.prop2).indexOf("yutu");
console.log(index);
The best & fastest way to do this is:
const products = [
{ prop1: 'telephone', prop2: 996 },
{ prop1: 'computadora', prop2: 1999 },
{ prop1: 'bicicleta', prop2: 995 },
];
const index = products.findIndex(el => el.prop2 > 1000);
console.log(index); // 1
I have seen many solutions in the above.
Here I am using map function to find the index of the search text in an array object.
I am going to explain my answer with using students data.
step 1: create array object for the students(optional you can create your own array object).
var students = [{name:"Rambabu",htno:"1245"},{name:"Divya",htno:"1246"},{name:"poojitha",htno:"1247"},{name:"magitha",htno:"1248"}];
step 2: Create variable to search text
var studentNameToSearch = "Divya";
step 3: Create variable to store matched index(here we use map function to iterate).
var matchedIndex = students.map(function (obj) { return obj.name; }).indexOf(studentNameToSearch);
var students = [{name:"Rambabu",htno:"1245"},{name:"Divya",htno:"1246"},{name:"poojitha",htno:"1247"},{name:"magitha",htno:"1248"}];
var studentNameToSearch = "Divya";
var matchedIndex = students.map(function (obj) { return obj.name; }).indexOf(studentNameToSearch);
console.log(matchedIndex);
alert("Your search name index in array is:"+matchedIndex)
You can use the Array.prototype.some() in the following way (as mentioned in the other answers):
https://jsfiddle.net/h1d69exj/2/
function findIndexInData(data, property, value) {
var result = -1;
data.some(function (item, i) {
if (item[property] === value) {
result = i;
return true;
}
});
return result;
}
var data = [{prop1:"abc",prop2:"qwe"},{prop1:"bnmb",prop2:"yutu"},{prop1:"zxvz",prop2:"qwrq"}]
alert(findIndexInData(data, 'prop2', "yutu")); // shows index of 1
function findIndexByKeyValue(_array, key, value) {
for (var i = 0; i < _array.length; i++) {
if (_array[i][key] == value) {
return i;
}
}
return -1;
}
var a = [
{prop1:"abc",prop2:"qwe"},
{prop1:"bnmb",prop2:"yutu"},
{prop1:"zxvz",prop2:"qwrq"}];
var index = findIndexByKeyValue(a, 'prop2', 'yutu');
console.log(index);
Try this code
var x = [{prop1:"abc",prop2:"qwe"},{prop1:"bnmb",prop2:"yutu"},{prop1:"zxvz",prop2:"qwrq"}]
let index = x.findIndex(x => x.prop1 === 'zxvz')
Another easy way is :
function getIndex(items) {
for (const [index, item] of items.entries()) {
if (item.prop2 === 'yutu') {
return index;
}
}
}
const myIndex = getIndex(myArray);
Georg have already mentioned ES6 have Array.findIndex for this.
And some other answers are workaround for ES5 using Array.some method.
One more elegant approach can be
var index;
for(index = yourArray.length; index-- > 0 && yourArray[index].prop2 !== "yutu";);
At the same time I will like to emphasize, Array.some may be implemented with binary or other efficient searching technique. So, it might perform better over for loop in some browser.
Why do you not want to iterate exactly ? The new Array.prototype.forEach are great for this purpose!
You can use a Binary Search Tree to find via a single method call if you want. This is a neat implementation of BTree and Red black Search tree in JS - https://github.com/vadimg/js_bintrees - but I'm not sure whether you can find the index at the same time.
One step using Array.reduce() - no jQuery
var items = [{id: 331}, {id: 220}, {id: 872}];
var searchIndexForId = 220;
var index = items.reduce(function(searchIndex, item, index){
if(item.id === searchIndexForId) {
console.log('found!');
searchIndex = index;
}
return searchIndex;
}, null);
will return null if index was not found.
var list = [
{prop1:"abc",prop2:"qwe"},
{prop1:"bnmb",prop2:"yutu"},
{prop1:"zxvz",prop2:"qwrq"}
];
var findProp = p => {
var index = -1;
$.each(list, (i, o) => {
if(o.prop2 == p) {
index = i;
return false; // break
}
});
return index; // -1 == not found, else == index
}
I am coding something in JS and I have to test code - I have to check if elements in 2 arrays are the same.
So I've got an array: boreholes = [[66000, 457000],[1111,2222]....]; and I want to check if this array contain element for eg. [66000,457000] so I did:
boreholes.indexOf([66000,457000]) but it returns -1, so I iterate trough array by:
for (var i = 0; i< boreholes.length; i++){
if (boreholes[i] == [66000, 457000]){
console.log('ok');
break;
}
};
but still I've got nothing. Can someone explain me what am I doing wrong?
You are comparing distinct objects. When comparing objects, the comparison only evaluates to true when the 2 objects being compared are the same object. I.E
var a = [1,2,3];
var b = a;
a === b //true
b = [1,2,3];
a === b //false, b is not the same object
To compare arrays like this, you need to compare all of their elements separately:
for (var i = 0; i < boreholes.length; i++) {
if (boreholes[i][0] == 66000 && boreholes[i][1] == 457000) {
console.log('ok');
break;
}
}
You cannot compare arrays like array1 == array2 in javascript like you're trying to do here.
Here is a kludge method to compare two arrays:
function isEqual(array1, array2){
return (array1.join('-') == array2.join('-'));
}
You can now use this method in your code like:
for (var i = 0; i< boreholes.length; i++){
if (isEqual(boreholes[i], [66000, 457000]){
console.log('ok');
break;
}
};
Currently I had the same problem, did it with the toString() method
var array1 = [1,2,3,[1,2,3]]
var array2 = [1,2,3,[1,2,3]]
array1 == array2 // false
array1.toString() == array2.toString() // true
var array3 = [1,2,3,[1,3,2]]
// Take attention
array1.toString() == array3.toString() // false
You could also doing it with the Underscore.js-framework for functional programming.
function containsElements(elements) {
_.find(boreholes, function(ele){ return _.isEqual(ele, elements); });
}
if(containsElements([66000, 457000])) {
console.log('ok');
}
The question isn't quite clear if there can be more than 2 elements in an array, so this might work
var boreholes = [[66000, 457000],[1111,2222]];
var it = [66000, 457000];
function hasIt(boreholes, check) {
var len = boreholes.length;
for (var a = 0; a < len; a++) {
if (boreholes[a][0] == check[0] && boreholes[a][1] == check[1]) {
// ok
return true;
}
}
return false;
}
if (hasIt(boreholes, it)) {
// ok, it has it
}
For some reason I'm having some serious difficulty wrapping my mind around this problem. I need this JS function that accepts 2 arrays, compares the 2, and then returns a string of the missing element. E.g. Find the element that is missing in the currentArray that was there in the previous array.
function findDeselectedItem(CurrentArray, PreviousArray){
var CurrentArrSize = CurrentArray.length;
var PrevousArrSize = PreviousArray.length;
// Then my brain gives up on me...
// I assume you have to use for-loops, but how do you compare them??
return missingElement;
}
Thank in advance! I'm not asking for code, but even just a push in the right direction or a hint might help...
Problem statement:
Find the element that is missing in the currentArray that was there in the previous array.
previousArray.filter(function(x) { // return elements in previousArray matching...
return !currentArray.includes(x); // "this element doesn't exist in currentArray"
})
(This is as bad as writing two nested for-loops, i.e. O(N2) time*). This can be made more efficient if necessary, by creating a temporary object out of currentArray, and using it as a hashtable for O(1) queries. For example:)
var inCurrent={}; currentArray.forEach(function(x){ inCurrent[x]=true });
So then we have a temporary lookup table, e.g.
previousArray = [1,2,3]
currentArray = [2,3];
inCurrent == {2:true, 3:true};
Then the function doesn't need to repeatedly search the currentArray every time which would be an O(N) substep; it can instantly check whether it's in currentArray in O(1) time. Since .filter is called N times, this results in an O(N) rather than O(N2) total time:
previousArray.filter(function(x) {
return !inCurrent[x]
})
Alternatively, here it is for-loop style:
var inCurrent = {};
var removedElements = []
for(let x of currentArray)
inCurrent[x] = true;
for(let x of previousArray)
if(!inCurrent[x])
removedElements.push(x)
//break; // alternatively just break if exactly one missing element
console.log(`the missing elements are ${removedElements}`)
Or just use modern data structures, which make the code much more obvious:
var currentSet = new Set(currentArray);
return previousArray.filter(x => !currentSet.has(x))
*(sidenote: or technically, as I illustrate here in the more general case where >1 element is deselected, O(M*N) time)
This should work. You should also consider the case where the elements of the arrays are actually arrays too. The indexOf might not work as expected then.
function findDeselectedItem(CurrentArray, PreviousArray) {
var CurrentArrSize = CurrentArray.length;
var PreviousArrSize = PreviousArray.length;
// loop through previous array
for(var j = 0; j < PreviousArrSize; j++) {
// look for same thing in new array
if (CurrentArray.indexOf(PreviousArray[j]) == -1)
return PreviousArray[j];
}
return null;
}
Take a look at underscore difference function: http://documentcloud.github.com/underscore/#difference
I know this is code but try to see the difference examples to understand the way:
var current = [1, 2, 3, 4],
prev = [1, 2, 4],
isMatch = false,
missing = null;
var i = 0, y = 0,
lenC = current.length,
lenP = prev.length;
for ( ; i < lenC; i++ ) {
isMatch = false;
for ( y = 0; y < lenP; y++ ) {
if (current[i] == prev[y]) isMatch = true;
}
if ( !isMatch ) missing = current[i]; // Current[i] isn't in prev
}
alert(missing);
Or using ECMAScript 5 indexOf:
var current = [1, 2, 3, 4],
prev = [1, 2, 4],
missing = null;
var i = 0,
lenC = current.length;
for ( ; i < lenC; i++ ) {
if ( prev.indexOf(current[i]) == -1 ) missing = current[i]; // Current[i] isn't in prev
}
alert(missing);
And with while
var current = [1, 2, 3, 4],
prev = [1, 2, 4],
missing = null,
i = current.length;
while(i) {
missing = ( ~prev.indexOf(current[--i]) ) ? missing : current[i];
}
alert(missing);
This is my approach(works for duplicate entries too):-
//here 2nd argument is actually the current array
function(previousArray, currentArray) {
var hashtable=[];
//store occurances of elements in 2nd array in hashtable
for(var i in currentArray){
if(hashtable[currentArray[i]]){
hashtable[currentArray[i]]+=1; //add 1 for duplicate letters
}else{
hashtable[currentArray[i]]=1; //if not present in hashtable assign 1
}
}
for(var i in previousArray){
if(hashtable[previousArray[i]]===0 || hashtable[previousArray[i]] === undefined){ //if entry is 0 or undefined(means element not present)
return previousArray[i]; //returning the missing element
}
else{
hashtable[previousArray[i]]-=1; //reduce count by 1
}
}
}
Logic is that i have created a blank array called hashtable. We iterate currentArray first and use the elements as index and values as counts starting from 1(this helps in situations when there are duplicate entries). Then we iterate through previousArray and look for indexes, if they match we reduce the value count by 1. If an element of 2nd array doesnt exist at all then our undefined check condition fires and we return it. If duplicates exists, they are decremented by 1 each time and when 0 is encountered, that elment is returned as missing element.