confused about indexOf(array[0]) - javascript

This is for a coderbyte challenge that I finished a while ago. Your function is supposed to get the second greatest and second lowest numbers heres what I originally used:
function SecondGreatLow(arr){
var sorted = arr.sort(function(a,b){
return a-b;
});
return sorted[1] + " " + sorted[arr.length - 2];
}
SecondGreatLow(readline());
I got two cases wrong with this function one of them being ([2,2,2,5,5,5,6]) because there are duplicate numbers. I implemented this into my new code :
function SecondGreatLow(arr) {
var exclude = [arr[0]];
for(var i = 1; i < arr.length; i++) {
if (exclude.indexOf(arr[i]) == -1) {
exclude.push(arr[i]);
}
}
return exclude
}
SecondGreatLow([33,33,33,44,44,44,55,55,6,4,3])
My question is how does this find all the duplicate numbers? Isn't the variable exclude(arr[0]) 33? I'm confused how this gets rid of all the duplicate numbers.

My question is how does this find all the duplicate numbers?
It actually doesn't find duplicate values, it collects unique values.
You iterate over the original array and add only values to exclude which are not already in exclude. That guarantees that every value in exclude is unique.
My question is how does it do this if exclude originally is only arr[0] or 33
This line:
var exclude = [arr[0]];
it just used to not start with an empty array. As you can see in the for statement
for(var i = 1; i < arr.length; i++) {
the code starts iterating at index 1, not 0. You could also just have started with an empty array:
var exclude = [];
for(var i = 0; i < arr.length; i++) {
but that's a bit wasteful since you know that the first value is going to be added to exclude anyway.

The way this code works is but adding new variables into the array exclude. It will only add the new variable if the current variable doesn't already exist in the array exclude.
The line:
exclude.indexOf(arr[i]) == -1
is what is doing main work.
It finds variable i and check if it already exists in the array exclude. If it does not exist indexOf returns -1, thus the if statement is true, and we go into the line
exclude.push(arr[i]);
and add the variable into the array exclude.

In the below loop
for(var i = 1; i < arr.length; i++) {
if (exclude.indexOf(arr[i]) == -1) {
exclude.push(arr[i]);
}
}
It is checking if the number from input array is already present in exclude if not it will insert that number to exclude.
The indexOf() method searches the array for the specified item, and returns its position. so in case of duplicate numbers it will not return -1 thus the logic above will skip adding that duplicate number to exculde variable. You can refer below for more details.
http://www.w3schools.com/jsref/jsref_indexof_array.asp

Related

All possible ways to combine array of strings uniquely [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 months ago.
Improve this question
How to combine array of strings in all possible ways
Example 1
input
const words = ["foo", "bar"]
Output
["foobar", "barfoo"]
Example 2
input
const words = ["word","good","best"];
Output
[
"wordgoodbest",
"wordbestgood",
"bestwordgood",
"bestgoodword",
"goodbestword",
"goodwordbest"
]
And so on if input size increased
function combineWords(words) {
const result = [];
if (words.length === 1) {
return words;
}
for (let i = 0; i < words.length; ++i) {
const word = words[i];
const rest = words.slice(0, i).concat(words.slice(i + 1));
const combinations = combineWords(rest);
for (let j = 0; j < combinations.length; ++j) {
result.push(word + combinations[j]);
}
}
return result;
}
// Example by OP in original question
console.log(combineWords(["word","good","best"]))
// Example by OP in comments
console.log(combineWords(["word", "good", "best", "hi"]))
// permutations are length of input factorial
console.log(combineWords(["word","good","best", "another", "more"]).length)
The function first checks if the array only contains one word. If so, it simply returns the array.
Otherwise, it loops through all the words in the array. For each word, it creates a new array that contains all the other words in the original array, excluding the current word. It then calls the function recursively on this new array, which will return an array of all possible combinations of the words in this new array.
Finally, it loops through all the combinations returned by the recursive call and appends the current word to each one, before adding it to the final array of results.
I don't know how efficient it would be but might get you what you need.
Remove duplicate entries from input array
outer loop n times (total no of elements in input array)
inner loop n-1 times (all elements except current outer loop)
Here's an alternative solution.
This creates a set of nested loops (one for each word in the set) using a recursive function. If within the innermost loop the indexes of all the loops comprise a unique set (no repeated numbers. i.e. 1,2,3,4 or 2,1,4,3.) Then pull each of the words in that order and add them to the results array.
function getCombinations(words){
const results = [];
const indexes = [];
const wordCount = words.length;
function looper(loopNumber){
for(indexes[loopNumber] = 0; indexes[loopNumber] < wordCount; indexes[loopNumber]++){
if(loopNumber < wordCount - 1){
looper(loopNumber + 1);
}
else {
if(indexes.length === new Set(indexes).size){
results.push(indexes.map(index => words[index]).join(''))
}
}
}
}
looper(0);
return results;
}
console.log(getCombinations(['a','b']));
console.log(getCombinations(['a','b','c']));
console.log(getCombinations(['a','b','c','d']));
console.log(getCombinations(["word","good","best"]));

Remove a user id from array of ids [duplicate]

I want to remove an element in an array with multiple occurrences with a function.
var array=["hello","hello","world",1,"world"];
function removeItem(item){
for(i in array){
if(array[i]==item) array.splice(i,1);
}
}
removeItem("world");
//Return hello,hello,1
removeItem("hello");
//Return hello,world,1,world
This loop doesn't remove the element when it repeats twice in sequence, only removes one of them.
Why?
You have a built in function called filter that filters an array based on a predicate (a condition).
It doesn't alter the original array but returns a new filtered one.
var array=["hello","hello","world",1,"world"];
var filtered = array.filter(function(element) {
return element !== "hello";
}); // filtered contains no occurrences of hello
You can extract it to a function:
function without(array, what){
return array.filter(function(element){
return element !== what;
});
}
However, the original filter seems expressive enough.
Here is a link to its documentation
Your original function has a few issues:
It iterates the array using a for... in loop which has no guarantee on the iteration order. Also, don't use it to iterate through arrays - prefer a normal for... loop or a .forEach
You're iterating an array with an off-by-one error so you're skipping on the next item since you're both removing the element and progressing the array.
That is because the for-loop goes to the next item after the occurrence is deleted, thereby skipping the item directly after that one.
For example, lets assume item1 needs to be deleted in this array (note that <- is the index of the loop):
item1 (<-), item2, item3
after deleting:
item2 (<-), item3
and after index is updated (as the loop was finished)
item2, item3 (<-)
So you can see item2 is skipped and thus not checked!
Therefore you'd need to compensate for this by manually reducing the index by 1, as shown here:
function removeItem(item){
for(var i = 0; i < array.length; i++){
if(array[i]==item) {
array.splice(i,1);
i--; // Prevent skipping an item
}
}
}
Instead of using this for-loop, you can use more 'modern' methods to filter out unwanted items as shown in the other answer by Benjamin.
None of these answers are very optimal. The accepted answer with the filter will result in a new instance of an array. The answer with the second most votes, the for loop that takes a step back on every splice, is unnecessarily complex.
If you want to do the for loop loop approach, just count backward down to 0.
for (var i = array.length - 0; i >= 0; i--) {
if (array[i] === item) {
array.splice(i, 1);
}
}
However, I've used a surprisingly fast method with a while loop and indexOf:
var itemIndex = 0;
while ((itemIndex = valuesArray.indexOf(findItem, itemIndex)) > -1) {
valuesArray.splice(itemIndex, 1);
}
What makes this method not repetitive is that after the any removal, the next search will start at the index of the next element after the removed item. That's because you can pass a starting index into indexOf as the second parameter.
In a jsPerf test case comparing the two above methods and the accepted filter method, the indexOf routinely finished first on Firefox and Chrome, and was second on IE. The filter method was always slower by a wide margin.
Conclusion: Either reverse for loop are a while with indexOf are currently the best methods I can find to remove multiple instances of the same element from an array. Using filter creates a new array and is slower so I would avoid that.
You can use loadash or underscore js in this case
if arr is an array you can remove duplicates by:
var arr = [2,3,4,4,5,5];
arr = _.uniq(arr);
Try to run your code "manually" -
The "hello" are following each other. you remove the first, your array shrinks in one item, and now the index you have follow the next item.
removing "hello""
Start Loop. i=0, array=["hello","hello","world",1,"world"] i is pointing to "hello"
remove first item, i=0 array=["hello","world",1,"world"]
next loop, i=1, array=["hello","world",1,"world"]. second "hello" will not be removed.
Lets look at "world" =
i=2, is pointing to "world" (remove). on next loop the array is:
["hello","hello",1,"world"] and i=3. here went the second "world".
what do you wish to happen? do you want to remove all instances of the item? or only the first one? for first case, the remove should be in
while (array[i] == item) array.splice(i,1);
for second case - return as soon as you had removed item.
Create a set given an array, the original array is unmodified
Demo on Fiddle
var array=["hello","hello","world",1,"world"];
function removeDups(items) {
var i,
setObj = {},
setArray = [];
for (i = 0; i < items.length; i += 1) {
if (!setObj.hasOwnProperty(items[i])) {
setArray.push(items[i]);
setObj[items[i]] = true;
}
}
return setArray;
}
console.log(removeDups(array)); // ["hello", "world", 1]
I must say that my approach does not make use of splice feature and you need another array for this solution as well.
First of all, I guess your way of looping an array is not the right. You are using for in loops which are for objects, not arrays. You'd better use $.each in case you are using jQuery or Array.prototype.forEach if you are using vanila Javascript.
Second, why not creating a new empty array, looping through it and adding only the unique elements to the new array, like this:
FIRST APPROACH (jQuery):
var newArray = [];
$.each(array, function(i, element) {
if ($.inArray(element, newArray) === -1) {
newArray.push(region);
}
});
SECOND APPROACH (Vanila Javascript):
var newArray = [];
array.forEach(function(i, element) {
if (newArray.indexOf(element) === -1) {
newArray.push(region);
}
});
I needed a slight variation of this, the ability to remove 'n' occurrences of an item from an array, so I modified #Veger's answer as:
function removeArrayItemNTimes(arr,toRemove,times){
times = times || 10;
for(var i = 0; i < arr.length; i++){
if(arr[i]==toRemove) {
arr.splice(i,1);
i--; // Prevent skipping an item
times--;
if (times<=0) break;
}
}
return arr;
}
An alternate approach would be to sort the array and then playing around with the indexes of the values.
function(arr) {
var sortedArray = arr.sort();
//In case of numbers, you can use arr.sort(function(a,b) {return a - b;})
for (var i = 0; sortedArray.length; i++) {
if (sortedArray.indexOf(sortedArray[i]) === sortedArray.lastIndexOf(sortedArray[i]))
continue;
else
sortedArray.splice(sortedArray.indexOf(sortedArray[i]), (sortedArray.lastIndexOf(sortedArray[i]) - sortedArray.indexOf(sortedArray[i])));
}
}
You can use the following piece of code to remove multiple occurrences of value val in array arr.
while(arr.indexOf(val)!=-1){
arr.splice(arr.indexOf(val), 1);
}
I thinks this code much simpler to understand and no need to pass manually each element that what we want to remove
ES6 syntax makes our life so simpler, try it out
const removeOccurences = (array)=>{
const newArray= array.filter((e, i ,ar) => !(array.filter((e, i ,ar)=> i !== ar.indexOf(e)).includes(e)))
console.log(newArray) // output [1]
}
removeOccurences(["hello","hello","world",1,"world"])

How to use an element of an array as an argument of indexOf method?

I have two arrays of values. I want to use the elements of one array to be the argument of an indexOf function. But I get a -1 (meaning value not found) even when I know the value exists in the array.
I have tested this by hard coding the value in the argument of indexOf so I know in this case that my problem is with cur_data variable. When I hard code the cur_data[x] with 'xyz' the indexOf returns correct index however when I use the array value [xyz] it returns -1.
What am I doing wrong?
function iterateSheets() {
var price_data = SpreadsheetApp.openById('1Nttb7XqUlZwGtmwbcRc3QkY3f2rxx7XdsdEU3cK4K4').getSheetByName('price').getRange("A2:A353").getValues()
var price_data2 = price_data.map(function(r) {
return r[0];
});
var test = new Array(30)
var ts = SpreadsheetApp.openById('18qFvVMVEE1k5DWUYaSezKeobcLr8I4oAmHLUpd_X99k');
var allShts = ts.getSheets();
for (var i = 0; i < 1; i++) //allShts.length //need to add in code to make sure tab is one of the fcst tabs
{
var cur_data = allShts[i].getRange("B8").getValues()
if (allShts[i].getName() == "July" || allShts[i].getName() ==
"Aug" || allShts[i].getName() == "Sept") {
for (var x = 0; x < 1; x++) {
Logger.log(cur_data[x])
Logger.log(price_data2.indexOf(cur_data[x]));
}
}
}
}
2D Array of values
getValues() method returns a two-dimensional Array of values from the Range that should be accessed via the values[row][column] schema. The for loop only increments the first dimension, that is, rows, and never accesses the value via column reference. Thus, you end up passing an Array instance to the indexOf() method.
Modification
You can add a second for loop to iterate over each of the elements of the Array of values, plus modify the first loop to make it more flexible just in case you ever need to loop over multiple rows:
for (var x = 0; x < cur_data.length; x++) {
for (var y = 0; y < cur_data[x].length; y++) {
Logger.log(cur_data[x][y])
Logger.log(price_data2.indexOf(cur_data[x][y]));
}
}
Comparison
indexOf() method performs search via the strict equality comparison and here is where the fun part starts. As Array instances are also Objects, meaning the same rules of comparison that apply to objects apply to them. This means that no two objects are equal (take a look at the comparison result table).
Useful links
getValues() reference;
indexOf() MDN reference;
Equality comparisons guide;

Removing duplicates from an array in Javascript [duplicate]

This question already has answers here:
Get all non-unique values (i.e.: duplicate/more than one occurrence) in an array
(97 answers)
Closed 8 years ago.
var data = localStorage.getItem('oldData').split(" ");
I am accessing localStorage as above and getting an array of values. Some of the elements are repeated in the string value for oldData, for example:
apples oranges apples apples
I want data to have only two elements apples and oranges. How can I do this in Javascript?
Array.prototype.unique = function(){
return Object.keys(this.reduce(function(r,v){
return r[v]=1,r;
},{}));
}
Strap it on. It's O(n) because using an object just requires you to loop through the array once and assign every value in it as a key, overwriting as you go. This only works when the values are primitives (or you have Harmony WeakMaps). But that's almost always the kind of array you want to do this one so it works out.
For bonus points here's the second best way to do it. This is at minimum twice as fast as the normal double loop answers and is at minimum as good as the ones requiring presorting,
(but still worse than the above hash method which is infinitely faster).
Array.prototype.unique = function(){
return this.filter(function(s, i, a){
return i == a.lastIndexOf(s);
});
}
The reason it beats every other answer aside from the hash is because it's able to get the benefit of sorting without doing the sorting step. It only searches from the current item forward, and from the other end in reverse, so there will never be a case where two items are checked against each other twice, and there will never be an unnecessary comparison done because it always quits at the very minimum amount of work needed to make a final decision. And it does all of this with the minimum possible creation of placeholder variables as a bonus.
first is to insert one value in your array by using push
var array = [];
array.push("newvalue");
then the next insertion of value, check if your value is existing in your array using "for loop". then if the value does not exist, insert that value using push() again
Array.prototype.unique = function()
{
var a = [];
var l = this.length;
for(var i=0; i<l; i++)
{
for(var j=i+1; j<l; j++)
{ if (this[i] === this[j]) j = ++i; }
a.push(this[i]);
}
return a;
};
Something like this should do the trick:
uniqueValues = function(array) {
var i, value,
l = array.length
set = {},
copy = [];
for (i=0; i<l; ++i) {
set[array[i]] = true;
}
for (value in set) {
if (set.hasOwnProperty(value)) {
copy.push(value);
}
}
return copy;
}
This is what I have used finally
var data = localStorage.getItem('oldData').split(" ");
var sdata = data.sort();
var udata = [];
var j = 0;
udata.push(sdata[0]);
for (var i = 1; i < data.length - 1; i += 1) {
if (sdata[i] != udata[j]) {
udata.push(sdata[i]);
j++;
}
}

Javascript / JQuery - How do I find the size of this array of objects?

I have this code to iterate through an array of objects:
for (vehicleIndex in scenes[sceneID].vehicles) {
vehicleID = scenes[sceneID].vehicles[vehicleIndex];
...
}
but I need to know how to determine the number of items being iterated through so that on the final item, I can execute a particular function. How do I do this?
Example in ES5:
Object.keys( scenes[sceneID].vehicles ).forEach(function( vehicle, index, arr ) {
if( index === arr.length - 1 ) {
// do something on last entry
}
});
Even tho, "last" just means the last element which was looped over. Since there is specific order within a Javascript object (they are infact unordered). However, we could sort the object key names manually by just chaining a .sort() before the .forEach()
var arraySize = scenes[sceneID].vehicles.length;
var i;
var currentItem;
for (i = 0; i < arraySize; i++) {
currentItem = scenes[sceneID].vehicles[i];
if (i == arraySize - 1) {
// do something special
} else {
// do something not so special ;-)
}
}
scenes[sceneID].vehicles should have a length property.
for (vehicleIndex in scenes[sceneID].vehicles) {
vehicleID = scenes[sceneID].vehicles[vehicleIndex];
...
}
doSomethingWithLastItem(vehicleId);
Because JS does not have block scope, by the time your loop finished vehicleId will be the last item's id.
In generic terms you can get the size of an array by accessing the .length property. You can also get the size of an object using Object.keys(obj).length.
Use this to find the length:
scenes[sceneID].vehicles.length
length is a built-in property in arrays. However, if you want to check for the last item, you have to check
scenes[sceneID].vehicles.length - 1
as arrays are zero-indexed.
Also, you should not use for...in to loop on arrays - if someone extends Array.prototype (or worse, Object.prototype), then you will not be happy. Use a normal for loop (which also allows you to use the final item easily):
var len = scenes[sceneID].vehicles.length;
for (var vehicleIndex = 0; vehicleIndex < len; vehicleIndex++) {
vehicleID = scenes[sceneID].vehicles[vehicleIndex];
//...
}
//Do something with the final item here
//Similar to this: itemFunc(vehicleID);
See this SO question for more details.

Categories