This simple comparison of jQuery objects does not compare - javascript

Curious what I'm doing wrong here :
employee_ids = $('[data-employee_id="'+employee+'"]');
timestamp_ids = $('[data-scheduled_on="'+timestamp+'"]');
var common = $.grep(timestamp_ids, function(element) {
$.each(employee_ids, function(idx, item) {
if ( item === element ) { console.log ("omg!") };
});
});
This returns just the list of timestamp_ids and not that array compared against employee_ids looking for a single match.

You are not using .grep correctly. Each iteration of grep should return a boolean: true to add it to the result array, false to ignore it.
var listA = [1, 2, 3];
var listB = [2, 3, 4];
var union = $.grep(listA, function (element) {
return listB.indexOf(element) !== -1;
});
Note that IE does not support .indexOf on Arrays, you will have to implement the comparison some other way.
EDIT: if you are trying to find a single item of an array that matches some criteria, i would suggest just using a regular for loop:
var result;
for (var i = 0; i < yourArray.length; i++) {
if (yourArray[i].id === employee_ID) { // whatever conditions you have
result = yourArray[i];
break;
}
}
if (result) {
// do whatever
} else {
// no match
}

Whatever else is wrong with that, it looks like the error is happening at $.grep
What is the typeof of timestamp_ids? According to the jQ docs, it needs to be an array.

Will this work?
employee_ids = $('[data-employee_id="'+employee+'"]');
timestamp_ids = $('[data-scheduled_on="'+timestamp+'"]');
var common = $.grep(timestamp_ids, function(element) {
return !($.inArray(element, timestamp_ids) == -1)
});

Whoa! Thanks for everyone's help. I just realized I could do this :
$('[data-employee_id="'+employee+'"][data-scheduled_on="'+timestamp+'"]');
I also realized I'm an idiot :(

Related

Compare and fill arrays - JS

a=['a','b','c']
b=['a','c']
I was trying to write a function that compares these both arrays and creates a third array filling the missing array member with null. So the return value should be:
['a',null,'c']
How do I do that?
P.S. Values are always in sequential order.
I am not sharing my try here because I don't want it to be improved or criticized, I know this function is not something hard to write (but it was for me) so I just want answers from experienced people.
You can use the Array.prototype.map function to loop over the a array and replace values.
var a = ['a','b','c'];
var b = ['a','c'];
var c = a.map(function(item) {
return ~b.indexOf(item) ? item : null;
});
console.log(c);
Hint: This only works if a contains at least all of the values that b contains.
A functional, but not necessarily the most efficient, solution:
var results = a.map(function(v) {
return b.indexOf(v) !== -1 ? v : null;
});
As the values are always sequential, it may be more efficient to loop with an index in each array, moving the index forward through b only when a match is found. Whether you actually want to do this as an optimisation depends on how big your arrays are.
Please try the following code,
var result = [];
a.forEach(function(item){
result.push(b.indexOf(item) < 0 ? null : item);
})
A slightly different approach without lookup with indexOf.
var a = ['a', 'b', 'a'],
b = ['a', 'b'],
c = a.map(function () {
var offset = 0;
return function (el, i) {
if (el === b[offset + i]) {
return el;
}
offset--;
return null;
}
}());
document.write('<pre>' + JSON.stringify(c, 0, 4) + '</pre>');

Check if variable contains any value of array

I have two arrays like so;
arr1 = ["foo.com", "bar.com"],
arr2 = ["//test.net/index.html", "http://www.bar.com", "https://foo.com/example.js"]
I'm iterating through arr2 and I want to omit the ones that contain any value of arr1.
Currently I'm using indexOf but that doesn't work if the values don't match exactly.
$.each(arr2, function(k,v){
if(arr1.indexOf(v) == -1)
console.log(v);
});
I'd hope for the above code to output
//test.net/index.html
since it's the only value of arr2 that doesn't contain any value of arr1. What am I doing wrong?
I would wrote two each loops for this:
arr1 = ["foo.com", "bar.com"],
arr2 = ["//test.net/index.html", "http://www.bar.com", "https://foo.com/example.js"]
$.each(arr2, function(x,y){
var found = false;
$.each(arr1, function(k,v){
if(!(y.indexOf(v) == -1)){
found = true;
return false;
}
});
if(!found){
console.log(y);
}
found= false;
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
You can use filter + some ES5 Array methods:
var arr1 = ["foo.com", "bar.com"],
arr2 = ["//test.net/index.html", "http://www.bar.com", "https://foo.com/example.js"];
var result = arr2.filter(function(val) {
return !arr1.some(function(el) {
return val.indexOf(el) !== -1;
});
});
alert(result);
Support for ES5 starts from IE9+, but if you need it to work in older IE, you can use polyfills (see links I provided), or it's pretty trivial to rewrite some part with simple for loop and use $.grep instead of Array.prototyp.filter.
It seems That you're using the Array version of indexOf, which doesn't work id the match is not exact.
With a little bit more setup, you can use the String version of indexOf
function compareValues (arr1, arr2){
var res = false;
$.each(arr2, function(k,v) {
checkAgainstArray(arr1, v);
});
function checkAgainstArray(arr1, value) {
$.each(arr1, function(k, v) {
if(value.indexOf(v) !== -1){
res = true;
}
});
}
return res;
}
//later on
var isValueInArray = compareValues(arr1, arr2);
(the code is not tested), but I Hope this helps
Try use the javascript RegExp to do the matching for each array element
http://www.w3schools.com/js/js_regexp.asp

find the array index of an object with a specific key value in underscore

In underscore, I can successfully find an item with a specific key value
var tv = [{id:1},{id:2}]
var voteID = 2;
var data = _.find(tv, function(voteItem){ return voteItem.id == voteID; });
//data = { id: 2 }
but how do I find what array index that object occurred at?
findIndex was added in 1.8:
index = _.findIndex(tv, function(voteItem) { return voteItem.id == voteID })
See: http://underscorejs.org/#findIndex
Alternatively, this also works, if you don't mind making another temporary list:
index = _.indexOf(_.pluck(tv, 'id'), voteId);
See: http://underscorejs.org/#pluck
Lo-Dash, which extends Underscore, has findIndex method, that can find the index of a given instance, or by a given predicate, or according to the properties of a given object.
In your case, I would do:
var index = _.findIndex(tv, { id: voteID });
Give it a try.
If you want to stay with underscore so your predicate function can be more flexible, here are 2 ideas.
Method 1
Since the predicate for _.find receives both the value and index of an element, you can use side effect to retrieve the index, like this:
var idx;
_.find(tv, function(voteItem, voteIdx){
if(voteItem.id == voteID){ idx = voteIdx; return true;};
});
Method 2
Looking at underscore source, this is how _.find is implemented:
_.find = _.detect = function(obj, predicate, context) {
var result;
any(obj, function(value, index, list) {
if (predicate.call(context, value, index, list)) {
result = value;
return true;
}
});
return result;
};
To make this a findIndex function, simply replace the line result = value; with result = index; This is the same idea as the first method. I included it to point out that underscore uses side effect to implement _.find as well.
I don't know if there is an existing underscore method that does this, but you can achieve the same result with plain javascript.
Array.prototype.getIndexBy = function (name, value) {
for (var i = 0; i < this.length; i++) {
if (this[i][name] == value) {
return i;
}
}
return -1;
}
Then you can just do:
var data = tv[tv.getIndexBy("id", 2)]
If your target environment supports ES2015 (or you have a transpile step, eg with Babel), you can use the native Array.prototype.findIndex().
Given your example
const array = [ {id:1}, {id:2} ]
const desiredId = 2;
const index = array.findIndex(obj => obj.id === desiredId);
you can use indexOf method from lodash
var tv = [{id:1},{id:2}]
var voteID = 2;
var data = _.find(tv, function(voteItem){ return voteItem.id == voteID; });
var index=_.indexOf(tv,data);
Keepin' it simple:
// Find the index of the first element in array
// meeting specified condition.
//
var findIndex = function(arr, cond) {
var i, x;
for (i in arr) {
x = arr[i];
if (cond(x)) return parseInt(i);
}
};
var idIsTwo = function(x) { return x.id == 2 }
var tv = [ {id: 1}, {id: 2} ]
var i = findIndex(tv, idIsTwo) // 1
Or, for non-haters, the CoffeeScript variant:
findIndex = (arr, cond) ->
for i, x of arr
return parseInt(i) if cond(x)
This is to help lodash users. check if your key is present by doing:
hideSelectedCompany(yourKey) {
return _.findIndex(yourArray, n => n === yourKey) === -1;
}
The simplest solution is to use lodash:
Install lodash:
npm install --save lodash
Use method findIndex:
const _ = require('lodash');
findIndexByElementKeyValue = (elementKeyValue) => {
return _.findIndex(array, arrayItem => arrayItem.keyelementKeyValue);
}
If you're expecting multiple matches and hence need an array to be returned, try:
_.where(Users, {age: 24})
If the property value is unique and you need the index of the match, try:
_.findWhere(Users, {_id: 10})
Array.prototype.getIndex = function (obj) {
for (var i = 0; i < this.length; i++) {
if (this[i][Id] == obj.Id) {
return i;
}
}
return -1;
}
List.getIndex(obj);
I got similar case but in contrary is to find the used key based on index of a given object's. I could find solution in underscore using Object.values to returns object in to an array to get the occurred index.
var tv = {id1:1,id2:2};
var voteIndex = 1;
console.log(_.findKey(tv, function(item) {
return _.indexOf(Object.values(tv), item) == voteIndex;
}));
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js"></script>
And If you want some particular key value from an object by id then use
var tv = [{id:1, name:"ABC"},{id:2, name:xyz}]
_.find(tv , {id:1}).value // retrun "ABC"

how to prevent adding duplicate keys to a javascript array

I found a lot of related questions with answers talking about for...in loops and using hasOwnProperty but nothing I do works properly. All I want to do is check whether or not a key exists in an array and if not, add it.
I start with an empty array then add keys as the page is scrubbed with jQuery.
Initially, I hoped that something simple like the following would work: (using generic names)
if (!array[key])
array[key] = value;
No go. Followed it up with:
for (var in array) {
if (!array.hasOwnProperty(var))
array[key] = value;
}
Also tried:
if (array.hasOwnProperty(key) == false)
array[key] = value;
None of this has worked. Either nothing is pushed to the array or what I try is no better than simply declaring array[key] = value Why is something so simple so difficult to do. Any ideas to make this work?
Generally speaking, this is better accomplished with an object instead since JavaScript doesn't really have associative arrays:
var foo = { bar: 0 };
Then use in to check for a key:
if ( !( 'bar' in foo ) ) {
foo['bar'] = 42;
}
As was rightly pointed out in the comments below, this method is useful only when your keys will be strings, or items that can be represented as strings (such as numbers).
var a = [1,2,3], b = [4,1,5,2];
b.forEach(function(value){
if (a.indexOf(value)==-1) a.push(value);
});
console.log(a);
// [1, 2, 3, 4, 5]
For more details read up on Array.indexOf.
If you want to rely on jQuery, instead use jQuery.inArray:
$.each(b,function(value){
if ($.inArray(value,a)==-1) a.push(value);
});
If all your values are simply and uniquely representable as strings, however, you should use an Object instead of an Array, for a potentially massive speed increase (as described in the answer by #JonathanSampson).
A better alternative is provided in ES6 using Sets. So, instead of declaring Arrays, it is recommended to use Sets if you need to have an array that shouldn't add duplicates.
var array = new Set();
array.add(1);
array.add(2);
array.add(3);
console.log(array);
// Prints: Set(3) {1, 2, 3}
array.add(2); // does not add any new element
console.log(array);
// Still Prints: Set(3) {1, 2, 3}
If you're already using spread...
let colors = ['red', 'orange', 'yellow'];
let moreColors = ['orange', 'green'];
let mergedColors = [...colors, ...moreColors];
and want to avoid duplicates...
let mergedColors = [...colors, ...moreColors.filter(c => !colors.includes(c)) ];
You can try this:
var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];
var uniqueNames = [];
$.each(names, function(i, el){
if($.inArray(el, uniqueNames) === -1) uniqueNames.push(el);
});
Easiest way to find duplicate values in a JavaScript array
The logic is wrong. Consider this:
x = ["a","b","c"]
x[0] // "a"
x["0"] // "a"
0 in x // true
"0" in x // true
x.hasOwnProperty(0) // true
x.hasOwnProperty("0") // true
There is no reason to loop to check for key (or indices for arrays) existence. Now, values are a different story...
Happy coding
function check (list){
var foundRepeatingValue = false;
var newList = [];
for(i=0;i<list.length;i++){
var thisValue = list[i];
if(i>0){
if(newList.indexOf(thisValue)>-1){
foundRepeatingValue = true;
console.log("getting repeated");
return true;
}
} newList.push(thisValue);
} return false;
}
var list1 = ["dse","dfg","dse"];
check(list1);
Output:
getting repeated
true
let x = "farceus";
let y = "character";
const commonCharacters = function (string1, string2) {
let duplicateCharacter = "";
for (let i = 0; i < string1.length; i += 1) {
if (duplicateCharacter.indexOf(string1[i]) === -1) {
if (string2.indexOf(string1[i]) !== -1) {
duplicateCharacter += string1[i];
}
}
}
return [...duplicateCharacter];
};
console.log(commonCharacters(x, y));

JS Sort - Determine if Anything Changed?

I'm using array.sort to sort an array of objects.
Is there someway to determine if the order of those objects changed other than doing a comparison myself? Some in-built JS function? I don't need to know the # of changes, just that there was at least 1 change.
Update:
I'm sorting custom objects, e.g.:
[
{ 'value' : 5, 'name' : 'foo'},
{ 'value' : 3, 'name' : 'bar'},
{ 'value' : 10, 'name' : 'js'}
]
Update 2:
I'm considering adding an additional custom property 'order' as I generate the objects and then checking to see if 'order' is or isn't sequential after the .sort. Is there a faster/better method?
There is nothing built in that does what you are asking. If it is a simple array you can just use join/toString() and compare the two final strings. If the array contains objects, probably would use JSON.stringify and compare.
var myArray1 = [1,2,3,4,5],
myArray2 = [2,1,3,4,5],
myArray1_sorted = myArray1.slice().sort(),
myArray2_sorted = myArray2.slice().sort();
//Check to see if the strings are the same or different
console.log( myArray1_sorted.toString() === myArray1.toString() ); //true - sort should not change anything
console.log( myArray2_sorted.toString() === myArray2.toString() ); //false - sort should have changed order
If you don't want to mess with two copies of the array, check the array before starting the sort.
You can loop through the array and return true if every item is in its sorted position,
(compares 'less' than the next item) or false as soon as one item is detected in the wrong position.
Since you are using objects, the comparison code depends on the way you are sorting the objects.
From Array.sort docs:
array.sort([compareFunction])
So it is obvious, there is no built-in solution/method for detecting whether at least one element has changed its position during the sorting. So you need to write your own method:
function isAnyElementChangedItsPosition( unsortedArray, sortedArray ){
for( var i = 0; i < unsortedArray.length; ++i){
if( unsortedArray[i] !== sortedArray[i] ){
return true;
}
}
return false;
}
You have to compare the arrays somehow. You can easily clone an array and make the check:
var arr = [5, 4, 1, 6]
var arrBefore = arr.slice(0);
arr.sort()
for(var i =0; i< arr.length; i++) {
if (arrBefore[i] !== arr[i]) {
// a change was made
}
}
In short: no built-in function, you've gotta check for equality.
Here's one way to check for equality:
function arraysEqual(a, b) {
// Are the lengths the same?
var i = a.length;
if (i !== b.length)
return false;
// Are all the values the same?
while (i --) {
if (a[i] !== b[i])
return false;
}
}
Note that this doesn't check if they're arrays; arraysEqual("abc", ["a", "b", "c"]) is true. You can add this check if you want.
There's not a built-in function to do what you want.
How about this:
function isArraySorted(array) {
if (!array.length) {
return true;
}
var lastElement = array[0];
for (var i = 1; i < array.length; i++) {
if (array[i] <= lastElement) {
return false;
}
lastElement = array[i];
}
return true;
}
alert(isArraySorted([1,2,3]) + " " + isArraySorted([1,2,3,2.5]));
var array = [1,2,3];
if (!isArraySorted(array)) {
// No need to do the sort if the array is already sorted.
array.sort();
}
Not duplicating data, becase strings and parallel arrays do.
function chkOrder(a) {
for(var i =1; i< a.length; i++)
if (a[i-1] > a[i]) return false;
return true;
}
you might need to work on th ">" sign if you reverse the order
this will also return false (not ordered) on first occourence
if we can control the contained objects then we can control changes in the objects and fire a parent sort
function O(parent,data) {//initialize with parent and value array/object
this.parent=parent;
this.data=data;
//shortcurt to sort parent
this.sort=function()
{console.log("sortingparent");this.parent.sort(this.parent.sortfunc);}
this.setData=function(data) {
this.data=data;
this.sort();
}
//if changes can be groupped then is more efficient to signal parent dirty and sort latter
this.setKey=function(key,value) {//change value in the data
if (key==parent.sortkey&&value!=this.data[key]) {
this.data[key]=value;
this.sort();
} else this.data[key]=value;
}
this.parent.push(this);
this.sort();
return this;
}
//-------
//using a simple array, this could also be and object and have specific func's
var arr=[];
//example, sort by name, ascending
arr.sortkey="name";
//closure to build a sort predicate bound to the used key
function setkey(key) {return function(a,b) {return a.data[key]>b.data[key];}}
arr.sortfunc=setkey(arr.sortkey);
var b=new O(arr,{name:"B",value:0});
var c=new O(arr,{name:"C",value:2});
var a=new O(arr,{name:"A",value:1});
var d=new O(arr,{name:"D",value:3});
console.log("changing value");
a.setKey("value",100);//when not sorting by value its the same as a.data.value=100
console.log("changing name");
a.setKey("name","X");//this will fire parent sort
for(n=0;n<arr.length;n++) console.log(arr[n].data.name,"=",arr[n].data.value);
var data = [
{ 'value' : 5, 'name' : 'foo'},
{ 'value' : 3, 'name' : 'bar'},
{ 'value' : 10, 'name' : 'js'}
];
var changed = sortAndReport(data, byValue);
// sortAndReport :: [a], (a, a -> Number) -> Boolean
// Sorts an array according to the provided Array.prototype.sort
// compare function and returns a Boolean indicating whether
// sorting changed the order of the array.
function sortAndReport(a, fn) {
var changed = false;
a.sort(function (a, b) {
var sortResult = fn(a, b);
changed = sortResult > 0;
return sortResult;
});
return changed;
}
// byValue :: { value :: Number }, { value :: Number } -> Number
function byValue(a, b) {
return a.value - b.value;
}

Categories

Resources