Backset is an array of arrays, I am trying to filter out any arrays which contain a repetition of elements, such as an array with 2 ones. I would like to remove these from the Backset array.
However this is not happening and some arrays in backSet such as [1,2,2] stay in backSet.
for(z=0; z<backSet.length; z++){
backSet[z].sort();
tempBackSort = [];
for(k=0; k< backSet[count].length; k++){
if(tempBackSort.includes(backSet[count][k])){
backSet.splice(backSet.indexOf(backSet[count]),1);
kon = 0;
continue;
} else{
tempBackSort.push(backSet[count][k]);
kon = 1;
}
}
if(kon===1){
count++;
}
backSet[z].sort();
}
There are several issues:
Where you have continue now it accomplishes nothing. You need break, so the inner loop is exited
You try to overcome the problem of iterating over an array where elements are sometimes removed by using count, but:
count is not initialised
You still have code that works with backSet[z] instead of backSet[count]
It would have been easier to just decrease z when an element is removed, or even better: to let the outer loop iterate backwards from end to start -- then you don't need to adjust any index.
Variables are implicitly declared as globals: this is bad practice. Define your variables with let or const.
By sorting the inner arrays, you mutate the original data. This might be OK for your case, but still it is maybe surprising for code that depends on this piece of code.
Sorting is also not the most efficient way to find duplicates. Instead of pushing values in tempBackSort, put them in a Set (which cannot contain duplicates) and compare its size with the original array: if their sizes are not the same, then there are duplicates.
Instead of splicing inside a loop (which is the cause of your trouble), use the array method filter which returns the filtered array.
Here is how it could be coded:
backSet = backSet.filter(arr => (new Set(arr)).size == arr.length);
Related
I've been teaching myself OOJS by creating a blackjack game. Everything is going great, but since I randomly create cards, sometimes I create and then deal the same card twice in a round. I'm trying to avoid that by writing some logic that gets rid of duplicate cards.
So I found this discussion.
https://stackoverflow.com/a/840849/945517
and the code below:
function eliminateDuplicates(arr) {
var i,
len=arr.length,
out=[],
obj={};
for (i=0;i<len;i++) {
obj[arr[i]]=0;
}
for (i in obj) {
out.push(i);
}
return out;
}
var a=[];
var b=[];
a[0]="fish";
a[1]="fishes";
a[2]="fish";
a[3]="1";
a[4]="fishes";
b=eliminateDuplicates(a);
console.log(a);
console.log(b);
I understand what's going on in general and on almost every line except:
for (i=0;i<len;i++) {
obj[arr[i]]=0;
}
It seems like it's looping through the array and setting the key of obj to zero. What's going on here and how does this help get rid of duplicate entries in the array being passed at the start?
Thanks!
{} = {key: value, key2:value2,....}
The above is essentially a key value map. The code iterates through the array and adds the key into the map with a value of zero. When the map tries to access an existing value, all it does is reset the value to zero. A useless operation, but it avoids an if..else or other more complex logic.
Once the array is done being iterated across, you only need to iterate across the key value map to get the keys. Since the keys are guaranteed to be unique, you have a list of unique items.
The main thing to realize here is that an object can only have one property per unique string, so when you set obj.fish to 0 when i = 0, you don't add a second "fish" property to obj when i = 2.
Then you can just loop through all of the properties of obj, each one is guaranteed to be unique, and thus you have stripped duplicates.
I haven't got any code yet, as I was just wondering if it is possible to loop through an Array that is dynamically populated to the amount of values could be different each time. The variables would obviously have to make use of an incrementing value?
You can use the array length property to work with an unknown array lengths:
var arr = ["carrots", "bananas", "onions"];
for (var i = 0, len = arr.length; i < len; i++) {
//every element accesible via arr[i];
//example:
console.log(arr[i]);
}
That will loop through the whole array even if it there are more or less elements on it
With this base, I am sure you can do what you want from here
I'm sure by now you've probably figured it out, but I'll just add this here for any future Javascript beginners.
Javascript Arrays have a built-in function called forEach allowing you to iterate over every element in an array. It functions as a loop specifically meant for Arrays. It takes a callback function as an argument and looks like the following:
let stringArr = ['dog', 'cat', 'lion', 'elephant'];
stringArr.forEach(function(element, counter) {
console.log(counter+') '+element);
});
// Outputs:
0) dog
1) cat
2) lion
3) elephant
The callback function can, of course be replaced by an arrow function, if you'd like, but as you can see the first argument in the callback function (element) is the element in the array, and the second argument (counter) keeps track of the index of the element in the array.
What I love about the forEach is that it makes accessing the array elements easier (even if only somewhat) than using a standard for-loop. For instance when looping through objects with a for-loop, to access the individual elements in the array one would have to do myArray[i].property, but using the forEach, one can simply do element.property.
Here's some additional reading on the forEach if it still hasn't quite clicked yet.
I want to remove an item from an array, is array.splice(x,1) the best way to go?
Is array.splice(x,1) functionally equivalent to delete array[x]; array.length-=1 ?
I've read these threads: Javascript object with array, deleting does it actually remove the item? and Deleting array elements in JavaScript - delete vs splice
and did some tests:
<script>
var arr=[];
for(var x=0;x<100000;++x){
arr.push(x);
}
var a=new Date().getTime();
for(var x=0;x<50000;++x){
arr.splice(49999,1);
}
var b=new Date().getTime();
alert(b-a);
</script>
<script>
var arr=[];
for(var x=0;x<100000;++x){
arr.push(x);
}
var a=new Date().getTime();
for(var x=0;x<50000;++x){
delete arr[49999];
arr.length-=1;
}
var b=new Date().getTime();
alert(b-a);
</script>
The timing difference is over a magnitude of 100, making the itch to use the second solution almost irresistable.. but before using it, I would like to ask this question: are there any traps i should look out for when i use delete array[x]; array.length-=1 instead of array.splice(x,1)?
If you're just lopping off the last element in the array, you can use pop() and throw away the result or just decrement the length by 1. The delete operator isn't even required here, and splice() is more appropriate for other uses.
Specifically, section 15.4 of the ECMAScript specification says:
whenever the length property is changed, every property whose name is an array index whose value is not smaller than the new length is automatically deleted.
Both methods mentioned are outlined at MDC:
Array pop()
Array length
Either are appropriate for your situation - by all means modify length if you get better performance from it.
array.splice may perform other internal operations relevant to the splice.
Your delete array[x]; array.length-=1 just hacks around the public interface and assumes that there's nothing else to do internally.
In fact, this is the cause of the timing difference: there is plenty more to do internally in order to actually splice the array.
Use the proper interface. That's why it's there.
Using delete does not delete the element. After delete somearr[n] somearr[n] still exists but its value is undefined. There are a few ways to remove elements from arrays.
within an array for one ore more elements: Array.splice
from the end of an array (i.e. the last element): Array.pop() or maybe Array.length = Array.length-1
from the beginning of an array (i.e. the first element): Array.shift() or Array.slice(1)
To be complete, using Array.slice you could make up a function too:
function deleteElementsFromArray(arr,pos,n){
return arr.slice(0,pos).concat(arr.slice(pos+n));
}
Deleting array elements just sets them to undefined - that's why it is so fast. It does not remove the element. Decreasing the length of the array makes it even worse as the array length doesn't change at all!
In other words: the response to your question title is no and you should use splice() to achieve the intended effect. You can use the delete 'trick' to achieve greater performance only if your code handles the possibility of undefined elements. That can be useful, but it has nothing to do with 'removing an item from an array'.
I just tried the for...in statement in Javascript.
This gives no error:
var images = document.getElementsByTagName('img');
for(x in images){
document.write(images[x]) + " ");
}
However, this does what it should but gives an error in the FF error console.
for(x in images){
images[x].style.visibility="visible";
}
This made me VERY curious as to what's going on.
Doing this:
for(x in images){
document.write(x);
}
...gave me this:
01234567891011121314151617lengthitemnamedItem
What's there at the end? I assume this makes the document.images / document.getElementsByTagName('img') array not suitable to use with the for...in statement since the values for x at the end won't correspond to an image? Maybe a for loop is better?
Don't iterate through arrays with for ... in loops. Use an index:
for (var i = 0; i < arr.length; ++i) {
// images[i] ...
}
The for ... in construct isn't wrong, it's just not what you want to do; it's for when you want to iterate through all properties of an object. Arrays are objects, and there are other properties besides the semantically-interesting indexed elements.
(Actually what comes back from getElementsByTagName isn't really an Array; it's a node list. You can however treat it like an array and it'll generally work OK. The same basic caveat applies for for ... in in any case.)
for..in does not loop through the indexes of an array, it loops through the enumerable property names of an object. It happens that the only enumerable properties array instances have, by default, are array indexes, and so it mostly works to think it does array indexes in limited situations. But that's not what for..in does, and misunderstanding this will bite you. :-) It breaks as soon as you add any further properties to the array (a perfectly valid thing to do) or any library you're using decides to extend the array prototype (also a valid thing to do).
In any case, what you get back from document.getElementsByTagName isn't an array. It's a NodeList. Your best bet for iterating through NodeLists is to use an explicit index a'la Pointy's answer -- e.g., a straight counting loop:
var i;
for (i = 0; i < list.length; ++i) {
// ... do your thing ...
}
Somewhat off-topic because it doesn't relate to your NodeList, but: When you are actually working with a real array, because arrays in JavaScript are sparse, there is applicability for for..in, you just have to be clear about what you're doing (looping through property names, not indexes). You might want to loop only as many times as the array has actual entries, rather than looping through all the indexes in the gaps in the sparse array. Here's how you do that:
var a, name;
a = [];
a[0] = "zero";
a[10000] = "ten thousand";
for (name in a) {
// Only process this property name if it's a property of the
// instance itself (not its prototype), and if the name survives
// transition to and from a string unchanged -- e.g., it's numeric
if (a.hasOwnProperty(name) && parseInt(name) == name) {
alert(a[name]);
}
}
The above only alerts twice, "zero" and "ten thousand"; whereas a straight counting loop without the checks would alert 10,001 times (mostly saying "undefined" because it's looping through the gap).
The problem with the for ... in construct is that everything from the prototype(s) gets included in the enumeration.
What your output is showing is basically every attribute of images, which is an array object. So you get
all the elements in your array, i.e. the numbers that appear in your output.
all the properties available on your array. This is why you see length in your output for example.
Your code breaks due to number 2, since a functions does not have a style attribute
So, yes, as Pointy shows, the correct way to iterate over the elements of an array in JavaScript is by using a for loop.
I want to iterate over two arrays at the same time, as the values for any given index i in array A corresponds to the value in array B.
I am currently using this code, and getting undefined when I call alert(queryPredicates[i]) or alert(queryObjects[i]).
I know my array is populated as I print out the array prior to calling this.
//queryPredicates[] and queryObjects[] are defined above as global vars - not in a particular function, and I have checked that they contain the correct information.
function getObjectCount(){
var variables = queryPredicates.length; //the number of variables is found by the length of the arrays - they should both be of the same length
var queryString="count="+variables;
for(var i=1; i<=variables;i++){
alert(queryPredicates[i]);
alert(queryObjects[i]);
}
The value of the length property of any array, is the actual number of elements (more exactly, the greatest existing index plus one).
If you try to access this index, it will be always undefined because it is outside of the bounds of the array (this happens in the last iteration of your loop, because the i<=variables condition).
In JavaScript the indexes are handled from 0 to length - 1.
Aside of that make sure that your two arrays have the same number of elements.
If queryPredicates does not have numerical indexes, like 0, 1, 2, etc.. then trying to alert the value queryPredicates[0] when the first item has an index of queryPredicates['some_index'] won't alert anything.
Try using a for loop instead:
stuff['my_index'] = "some_value";
for (var i in stuff)
{
// will alert "my_index"
alert(i);
// will alert "some_value"
alert(stuff[i]);
}
Arrays in JS are zero based. Length is the actual count. Your loop is going outside the bounds of the array.