I am trying to determine whether a object contains a specific value so that I can be sure not append the value I am looking for more than once and prevent recursion.
I have tried lots of methods but can't get any of them to work:
data = [
{val:'xxx',txt:'yyy'},
{val:'yyy',txt:'aaa'},
{val:'bbb',txt:'ccc'}
];
console.log(jQuery.grep(data, function(obj){
return obj.txt === "ccc";
}));
$.map(data, function(el) {
if(el.txt === 'ccc')
console.log('found')
});
Can this be done with map() grep() or inArray() or do I really have to loop through the entire array looking for the value ??
data is an array containing multiple objects, so you'll need to specify the index of the array you wish to look in:
data[0].val === 'xxx';
data[1].val === 'yyy';
data[2].txt === 'ccc';
As an update to your function, what's wrong with $.each? You're looping anyway with map or grep, so you may as well just be honest about it :P You can loop with for as well, but I'm exampling with $.each as it's almost identical to your current code.
$.each(data, function(el) {
if(el.txt === 'ccc')
console.log('found')
});
You will have to iterate the whole array as it's an array of objects, and comparing objects is done by the references not by the values.
for (var i = 0; i < data.length; i++){
if (data[i].val == 'something')
doSomething();
}
var stExist=$.inArray(reqelement, dataArray)
If you wish to avoid all this calculations yourself, there is a utility plugin underscore.js, which has lots of helper.
One of the helpers you are looking for http://underscorejs.org/#contains.
Related
To simplify my question, suppose the objects are jqlite objects, using the angular.equals function, I can check whether they are equal. My question is: How do we use this function to remove duplicate item from an array of jqLite objects?
Here is what I tried:
// Suppose jqArr is the array stated above:
var result = [];
angular.forEach(jqArr, function(v_i){
if(result.length === 0){
result.push(v_i);
} else {
var isPushed = false;
angular.forEach(result, function(v_j){
if(angualr.equals(v_i, v_j)){
isPushed = true;
}
});
if(isPushed === false){
result.push(v_i);
}
}
})
console.log(result);
Suppose jqArr = [e_1, e_2, e_3, e_1, e_2], where e_i(s) are jQLite elements.
output should be:
[e_1, e_2, e_3]
*Please answer using only javascript and angularJs.
You can use ES6 Set like so:
let arr = [1,1,2,2,2,3,4,5,6,6,6,6,6];
let uniq = [...new Set(arr)];
The uniq array will contain unique values. If the aray is filled with object references, it will naturally work too.
In a more abstract form, you are performing an O(n^2) algorithm (same with indexOf and Set) but you can reduce the complexity to O(nlogn) by adding all the elements to the list without checks, after all the elements have been collected remove the duplicates be sorting (needs only one pass over the array to remove duplicates after sort).
This solution works only if you can store all the duplicates, for a "duplication factor" above 100% this is not efficient.
If you cannot perform a logic sort, hash function can give the same result.
I have an array of elements which I want to maintain efficiently, adding and removing arrays of elements over time.
var myElements = $('.initial');
jquery's merge() seems perfect for adding items as it doesn't create a new array and just adds to the existing one:
$.merge(myElements, $('.to-add'));
Is there an equivalent for removing, that also modifies the array in-place? Something like:
$.exclude(myElements, $('.to-remove'));
I do actually have arrays of DOM elements, and the selectors are just used as examples.
Assuming that you're after the relative complement of b in a.
And you don't want to create additional objects while process.
The function is for both plain Array and jQuery set.
(thus used $.each, $.inArray instead of Array.prototype.forEach Array.prototype.indexOf)
I wrote a function that fits your requirement.
$.exclude = function(a,b) {
var idx;
$.each(b, function(i, val) {
while((idx = $.inArray(val, a)) !== -1) {
a.splice(idx, 1);
}
})
return a;
}
test this code here
https://jsfiddle.net/happyhj/uwd4L1dm/8/
and you can use like this.
$.exclude(myElements, $('.to-remove'));
use jquery not method,
var filtered = $(myElements).not($('.to-remove'));
You can use delete to remove an element from an array and then use $.grep to remove the empty space.
//[0] since $("#id") will be a jquery Object
//[0] will return the particular DOM element
var orgArray = [$("#merge1")[0],$("#merge2")[0],$("#merge3")[0]];
var secArray = [$("#merge4")[0],$("#merge5")[0]]
// Will merge other two values;
// jQuery merge will merge contents of
//two array into first array
var merArray = $.merge(secArray, orgArray);
// Want to remove $("#merge2");
var getIndex = merArray.indexOf($("#merge2")[0]);
if(getIndex >-1){
delete merArray[getIndex]
}
// length before filtering
$("#l1").text(merArray.length);
//Now will remove Empty Space
merArray = $.grep(merArray,function(n){
return n==0 || n
});
$("#l2").text(merArray.length);
JSFIDDLE
You are using methods that are meant for array literals. jQuery already has method add() which will return a modified jQuery object that includes the elements matching the selector
var myElements = $('.initial');
var newCollection = myElements.add('.to-add');
newCollection.not('.to-remove').doSomething();
Don't think of jQuery objects as arrays although they are array like.
Reference add()
It's not clear what your overall objective really is but most likely you can manage it with any number of filtering methods that already exist within the api
All:
Say I have an array of object, each one has value attr.
What I want to do is :
Loop thru the array and remove the objects whose value is less than 1,
I thought of using splice or create another array, push those whose value>=1 into it then return new array, I wonder which way is better? Or any other efficient way?
Thanks
If you want to keep the original array intact:
arr.filter(function(elem) {
return elem.value >= 1;
})
My reading of your question led me to understand that each array element has a value property. If, instead, each element is just the actual value being compared, then replace "elem.value" with "elem".
[UPDATE]
Based on a jsperf comparison, if you are OK with modifying the original array, the splice approach presented in #NicholasHazel's answer is actually an order of magnitude faster.
I even tried a third approach using slice() to first make a copy of the original array, and then using splice() on the copy, but that was much slower than the other approaches.
Internally splice is doing a new array, so behind the scenes you'll create new array for every object you want to remove. This means creating one array an pushing to it only wanted objects is much more efficient than splice.
For efficiency sake, splice will be your most optimum performance solution.
As long as you don't need the initial array any more, I would just convert the variable entirely.
var array = [-5,-4,-3,-2,-1,0,1,2,3,4,5];
for(var i=array.length-1; i>=0; i--){
if(array[i] < 1) {
array.splice(i,1);
}
}
If you do have a need to utilize the initial array at a later time, pushing to a new array is your best bet:
var array = [-5,-4,-3,-2,-1,0,1,2,3,4,5];
var newArray = [];
for(var i=array.length-1; i>=0; i--){
if(array[i] < 1) {
newArray.push(array[i]);
}
}
Both are perfectly reasonable solutions.
From the question if you are talking about array of object below is the solution which will keep intact the original array and its more efficient as well.
Use delete operator which will put undefined on indexes which have value<=1
<!doctype html>
<html>
<head>
<script>
var obj1 = {
value: 0
};
var obj2 = {
value: 10
};
var arr = [obj1, obj2];
arr.forEach(function(x, counter, arr) {
if (arr[counter].value <= 1)
delete arr[counter];
});
arr.forEach(function(x, counter, arr) {
document.write(arr[counter].value);
});
</script>
</head>
</html>
When I'm working with data, I normally have the need of create Arrays or Objects on a loop, let's say "on the fly".
Lets say for example I want to rearrange an array grouping the element by one of the array keys: One of the methods I use is to loop trough an for in. But the problem is when I define more than one index on the fly.
for(key in array){
newArray[array[key]['gouping_key']] = array[key];
}
This example works fine. But if you have more than one element with the same grouping_key, this code is going to override your previous element.
So, I try this:
var i = 0;
for(key in array){
newArray[array[key]['gouping_key']][i] = array[key];
i++
}
But when I add that second index the interpreter complains saying that the newArray[array[key]['gouping_key']] is undefined. Problem it doesn´t seems to have on the previous example.
Why is that?
I've made this fiddle with an example in case the previous snippets an explanation would be insuficient and unclear. In the fiddle you have three snippets (two commented out).
The first one is the error I get when trying something like what Iǘe mentioned previously.
The second is the solution I use.
And the third an example of the creation of an array on the fly with only one index.
Summing up, I want to know why, when you add the second index, you get that error.
Thanks!
var i = 0;
for(key in array){
// If nested object doesn't exist, make an empty one.
newArray[array[key]['gouping_key']][i] =
newArray[array[key]['gouping_key']][i] || [];
newArray[array[key]['gouping_key']][i] = array[key];
i++
}
You need to create an array to push to, it's not created for you. You can use the || operator to only create an empty array if it's undefined.
Also, that's a lot of nesting to follow... If I may...
var x, y;
y = 0;
for(key in array){
x = array[key].gouping_key;
newArray[x][y] = newArray[x][y] || []
newArray[x][y] = array[key];
y++
}
See how much more readable that is? It's also faster! You dont have to deeply traverse complex objects over and over again.
First using for in for arrays is no good idea, it does not what you are expecting I think. see: https://stackoverflow.com/a/4261096/1924298. Using a simple for loop (or while) should solve your problem.
I have a string that has data separated by a pipe character (|).
Example
var somestring = "data1|data2|data3";
var separated = somestring.split("|");
I know how to use the split() to separate each data.
However, I don't know how many pipes there will be in the resulting Array.
In jQuery or JavaScript, how do I loop over the array returned?
In jQuery or JavaScript, how do I loop through each separated variable?
You basically just need to iterate over the resulting Array.
jQuery
$.each loop
This method is easy to work with, and benefits in the variables used being encapsulated.
$.each(separated, function(index, chunk) {
// `chunk` is each member of the array.
});
jsFiddle.
Of course, jQuery is JavaScript so any of the below methods will also work.
JavaScript
for loop
This is the recommended way.
for (var i = 0, length = separated.length; i < length; i++) {
var chunk = separated[i];
// `chunk` is each member of the array.
}
jsFiddle.
You'll notice too the length property is cached so it is not looked up on each iteration. Some browsers already optimise for this, however IE appears to still benefit from it cached. It only takes 5 seconds to do, so you may as well keep IE users happy too.
You may want to define i and chunk outside of the for loop, because JavaScript has no block scope (unless you're using let), and those variables will exist before (declaration hoisted) and after (no block scope).
for ( in ) loop
This loop is generally not recommended, as it should be used for iterating over object properties only, not array like member properties.
for (var chunk in separated) {
if ( ! separated.hasOwnProperty(chunk)) {
continue;
}
// `separated[chunk]` is each member of the array.
}
jsFiddle.
This loop will loop over all properties up the prototype chain, so hasOwnProperty() must be used. For this reason it is not recommended for arrays.
for ( of ) loop
This loop is standardized in ECMA 6 and is able to loop over NodeLists and iterators.
for (var chunk of separated) {
// `chunk` is each member of the array.
}
jsFiddle
forEach() method
This method is an addition to the ECMA-262 standard. It's not available in IE8, but it can be shimmed relatively easily.
separated.forEach(function(chunk, index) {
// `chunk` is each member of the array.
});
jsFiddle.
Other specialised methods
If you're looking to iterate for a specific goal, it may be useful to use a specialised iterator. Keep in mind these also don't have the best browser support.
filter method
Creates a mew array of the elements which the associated callback returned truthy for.
separated.filter(function(element) {
return +element > 255;
});
reduce method
Creates a new value based on reducing the elements of the array, from left to right.
separated.reduce(function(accumulator, element) {
return accumulator.concat(element);
}, "");
See also the reduceRight method.
map method
Creates a new array, replacing each element with the returned value of the associated callback.
separated.map(function(element) {
return element.substr(0, 1);
});
every method
Returns a boolean value of which is the result of every element in the array passing the test. This method short circuits, i.e. it returns whenever one element's callback doesn't return truthy.
separated.every(function(element) {
return element.substr(0, 1) == "a";
});
some method
Returns a boolean value of which is the result of some element in the array passing the test. This method short circuits, i.e. it returns whenever one element's callback passes the test.
separated.some(function(element) {
return element.substr(0, 1) == "a";
});
separated.length should be all you need.
str.split() returns an array of values, so in your example, since 'separated' is an array, you could:
for (var i=0, len=separated.length; i < len; i++) {
// do something with separated[i]
}
you can do it in jquery like this
$.each(separated,function(key,item){ alert('here is ' + item + ' at position ' + key) })
If your question really is "how do I loop through each separated variable?" then:
for (var i = 0; i < separated.length; i++)
{
//Do something with separated[i];
}
//or (apparently this is deprecated)
for(var a in separated)
{
//Do something with a
}
Loop through with a FOR...NEXT construct like in most other languages:
var somestring = "data1|data2|data3";
var separated = somestring.split("|");
for (i=0 ; i<separated.length; i++) {
document.write(separated[i]);
document.write("<br/>");
}