finding all missing elements in an array/range javascript - javascript

I am trying to to write a function to find all missing elements in an array. The series goes from 1...n. the input is an unsorted array and the output is the missing numbers.
below is what I have so far:
function findMissingElements(arr) {
arr = arr.sort();
var missing = [];
if (arr[0] !== 1) {
missing.unshift(1);
}
// Find the missing array items
for (var i = 0; i < arr.length; i++) {
if ((arr[i + 1] - arr[i]) > 1) {
missing.push(arr[i + 1] - 1);
}
}
return missing;
}
var numbers = [1, 3, 4, 5, 7, 8]; // Missing 2,6
var numbers2 = [5, 2, 3]; //missing 1, 4
var numbers3 = [1, 3, 4, 5, 7]; // Missing 2,6
console.log(findMissingElements(numbers)); // returns 2,6 correct
console.log(findMissingElements(numbers2)); // returns 1,4
console.log(findMissingElements(numbers3)); // returns 2, 6
I "manually" checked for the first element with an if block, is there any way to handle the case of the first element inside the for loop?

You can produce that by tracking which number should appear next and adding it to a list of missing numbers while it is less than the next number.
function findMissingElements(arr) {
// Make sure the numbers are in order
arr = arr.slice(0).sort(function(a, b) { return a - b; });
let next = 1; // The next number in the sequence
let missing = [];
for (let i = 0; i < arr.length; i++) {
// While the expected element is less than
// the current element
while (next < arr[i]) {
// Add it to the missing list and
// increment to the next expected number
missing.push(next);
next++;
}
next++;
}
return missing;
}

A not so efficient but more intuitive solution:
var n = Math.max.apply(null, arr); // get the maximum
var result = [];
for (var i=1 ; i<n ; i++) {
if (arr.indexOf(i) < 0) result.push(i)
}

Aside from the fact that your tests are not consistent, this feels a bit neater to me:
function findMissingElements (arr, fromFirstElement) {
arr.sort();
var missing = [];
var next = fromFirstElement ? arr[0] : 1;
while(arr.length) {
var n = arr.shift();
while (n != next) {
missing.push(next++);
}
next++;
}
return missing;
}
var numbers = [1, 3, 4, 5, 7, 8]; // Missing 2,6
var numbers2 = [5, 2, 3]; // Missing 1, 4
var numbers3 = [1, 3, 4, 5, 7]; // Missing 2, 6
console.log(findMissingElements(numbers)); // returns 2, 6
console.log(findMissingElements(numbers2)); // returns 1, 4
console.log(findMissingElements(numbers3)); // returns 2, 6
I've added an argument fromFirstElement which, if passed true, will enable you to start from a number defined by the first element in the array you pass.

Related

How to return an array of indexes from the first array which is the intersection of indexes from two sorted arrays?

I wrote a solution that allows me to get an array of indexes from the first array which is the intersection of indexes from two sorted arrays and I'd like to know why this solution is wrong. When I check it I get the correct array of indexes from the first array but the interviewer told me that this is wrong.
Thanks a lot for the help and explanations. I have no commercial experience yet. Sorry for some mistakes in English, as I am from Ukraine and I improve this language.
// first example of input:
// const arr1 = [1, 2, 2, 2];
// const arr2 = [1, 1, 2, 2];
// second example of input:
const arr1 = [1, 2, 2, 3, 4, 5, 6, 7, 9, 9, 20];
const arr2 = [1, 2, 3, 3, 5, 8, 9, 9, 21];
// first example of output:
// - [0, 1, 2]
// - [0, 1, 3]
// - [0, 2, 3]
// second example of output:
// - [0, 1, 3, 5, 8, 9]
// - [0, 2, 3, 5, 8, 9]
//function compareItemsFn, length1, length2 - from conditions to this task
const compareItemsFn = (index1, index2) => {
switch (true) {
case arr1[index1] === arr2[index2]: return 0;
case arr1[index1] < arr2[index2]: return -1;
case arr1[index1] > arr2[index2]: return 1;
default: return undefined;
}
};
const length1 = arr1.length;
const length2 = arr2.length;
// function intersectionIndexes - my solution
function intersectionIndexes(compareItemsFn, length1, length2) {
let indexesIntersectionArray = [];
let i = 0;
let j = 0;
while (i < length1 && j < length2) {
if (compareItemsFn (i, j) === 0) {
indexesIntersectionArray.push(i);
i++;
j++;
} else if (compareItemsFn (i, j) === 1) {
j++;
} else {
i++;
}
}
return indexesIntersectionArray;
};
const result = intersectionIndexes(compareItemsFn, length1, length2);
If you are certain that your solution works then perhaps it was not wrong in the sense that it gave the wrong answer but rather in the way you solved the problem.
The following code is a simplification of your solution. It takes the two arrays as parameters instead of the value of their length property so the solution isn't tied to the global variables arr1 and arr2. You should always favor implementing solutions that are generalised.
In place of your compareItemsFn function, the Math.sign() method from the standard library is used. Some times in interview situations you can be asked to implement functionality which can be found in the standard library and what the interviewer is looking to see is if you are aware of it.
function simplified(arrayOne, arrayTwo) {
let result = [];
let indexOne = 0;
let indexTwo = 0;
while (indexOne < arrayOne.length && indexTwo < arrayTwo.length) {
let signCheck = Math.sign(arrayOne[indexOne] - arrayTwo[indexTwo]);
if (signCheck == 0) {
result.push(indexOne);
indexOne++;
indexTwo++;
}
else if ( signCheck > 0) {
indexTwo++;
}
else {
indexOne++;
}
}
return result;
}

How to find index of first duplicate in array in Javascript?

const numbers = [2, 4, 5, 2, 3, 5, 1, 2, 4];
I need to create the function indexOfRepeatedValue (array). Use numbers that are stored in the variable numbers.
I should create a variable firstIndex in this function. In the for loop, check which number repeats first and assign its index to firstIndex. Then write this variable to the console - outside of the for loop.
I came up with this idea It doesn't work at all. I'm lost, some piece of advice?
const numbers = [2, 4, 5, 2, 3, 5, 1, 2, 4];
function indexOfRepeatedValue(array) {
let firstIndex;
for (let i = 0; i < array.length; i++)
if (firstIndex.indexOf(array[i]) === -1 && array[i] !== '');
firstIndex.push(array[i]);
return firstIndex;
}
console.log(
indexOfRepeatedValue(numbers)
)
Start by making firstIndex an array: let firstIndex = [];
Then make sure the i is not outside the scope you used since you use let.
You end the statement with a semicolon, that means the loop never does the next line
Then return the first number found that is in your new array
Note JS Arrays start at 0, so the result is 3, since the second number 2 is in the 4th place
I have kept my code as close to yours as possible.
const numbers = [2, 4, 5, 2, 3, 5, 1, 2, 4];
function indexOfRepeatedValue(array) {
let firstIndex = [];
for (let i = 0; i < array.length; i++) {
if (firstIndex.indexOf(array[i]) !== -1) { // we found it
console.log("found",array[i], "again in position", i)
console.log("The first of these is in position",numbers.indexOf(array[i]))
return i; // found - the function stops and returns
// return numbers.indexOf(array[i]) if you want the first of the dupes
}
firstIndex.push(array[i]); // not found
}
return "no dupes found"
}
console.log(
indexOfRepeatedValue(numbers)
)
There are many more ways to do this
Javascript: How to find first duplicate value and return its index?
You could take an object for storing the index of a value and return early if the index exist.
function indexOfRepeatedValue(array) {
let firstIndex = {};
for (let i = 0; i < array.length; i++) {
if (firstIndex[array[i]] !== undefined) return firstIndex[array[i]];
firstIndex[array[i]] = i;
}
return -1;
}
const numbers = [2, 4, 5, 2, 3, 5, 1, 2, 4];
console.log(indexOfRepeatedValue(numbers));
Start by initializing firstIndex:
let firstIndex = [];
Use the following to find the index of each repeated element:
if( array.slice(0,i).includes(array[i]) ) {
firstIndex.push( i );
}
If you need the absolute first index of a repeat:
return firstIndex[0];
//Please note that if this is your goal then you do not even need the variable firstIndex, nor do you need to run through the whole loop.
If you need indices of all repeated elements:
return firstIndex;
const numbers = [2, 4, 5, 2, 3, 5, 1, 2, 4];
function indexOfRepeatedValue(array) {
let firstIndex = [];
for (let i = 0; i < array.length; i++)
if( array.slice(0,i).includes(array[i]) ) {
firstIndex.push(i);
}
return firstIndex[0];
}
console.log(
indexOfRepeatedValue(numbers)
)
NOTE
Alternatively, you can use Array#map to get index of repeated values then use Array#filter to retain only those indices, the first [0] is what you're lookin for.
const numbers = [2, 4, 5, 2, 3, 5, 1, 2, 4];
const indexOfRepeatedValue = arr =>
arr.map((a,i) => arr.slice(0,i).includes(a) ? i : -1)
.filter(i => i > -1)[0];
console.log( indexOfRepeatedValue( numbers ) );

Find the number that repeat times in the no.N place

have a array such as [1,3,5,7,9,1,2,3,5,7,7,9,9,9] we can cout the times every number appear,the number 9 appear 4 time , the number 7 appear 3 time ...then how can i do to get the number that appear in no.N place ;
It mean if i want to find the no.1 it's 9,no.2 it's 7
function findFrequenceNumber(arr,n){
var count={};
for(var i=0,len=arr.length;i<len;i++){
if(!count[arr[i]]) count[arr[i]]=1;
else count[arr[i]]++;
}//I save the record in a object {num:times}
}
Try this:
var nums = [1,3,5,7,9,1,2,3,5,7,7,9,9,9];
function reArrangeByAppearingTimes(arr){
var i, appearingTimes = {}, sortableAppearingTimes = [];
// Looping over the array to get every element appearing times. sotred in OBJECT
for (i = 0; i < arr.length; i += 1){
appearingTimes[arr[i]] = appearingTimes[arr[i]] ? (appearingTimes[arr[i]] + 1) : 1;
}
// converting Object to Array (for sorting purpose)
for (var key in appearingTimes) {
sortableAppearingTimes.push([key, appearingTimes[key]]);
}
// Sorting the array
sortableAppearingTimes.sort(function(a, b) {
return b[1] - a[1];
});
// Using map to get only need values (removing appearing times)
return sortableAppearingTimes.map(function (smallArr) {
return smallArr[0]
});
}
console.log(reArrangeByAppearingTimes(nums));
You could get all keys form the object,sort it descending and take the wanted item at the nth position.
function findFrequenceNumber(arr, n){
var count = {}, keys;
for (var i = 0, len = arr.length; i < len; i++){
if(!count[arr[i]]) {
count[arr[i]] = 1;
} else {
count[arr[i]]++;
}
}
keys = Object.keys(count).sort(function (a, b) { return count[b] - count[a]; });
console.log('keys', keys);
return keys[n - 1];
}
console.log(findFrequenceNumber([1, 3, 5, 7, 9, 1, 2, 3, 5, 7, 7, 9, 9, 9], 1));
console.log(findFrequenceNumber([1, 2, 3, 3, 1, 1, 1, 1], 1));

Find the first repeated number in a Javascript array

I need to find first two numbers and show index like:
var arrWithNumbers = [2,5,5,2,3,5,1,2,4];
so the first repeated number is 2 so the variable firstIndex should have value 0. I must use for loop.
var numbers = [7, 5, 7, 6, 6, 4, 9, 10, 2, 11];
var firstIndex
for (i = numbers[0]; i <= numbers.length; i++) {
firstIndex = numbers[0]
if (numbers[i] == firstIndex) {
console.log(firstIndex);
break;
}
}
You can use Array#indexOf method with the fromIndex argument.
var numbers = [7, 5, 7, 6, 6, 4, 9, 10, 2, 11];
// iterate upto the element just before the last
for (var i = 0; i < numbers.length - 1; i++) {
// check the index of next element
if (numbers.indexOf(numbers[i], i + 1) > -1) {
// if element present log data and break the loop
console.log("index:", i, "value: ", numbers[i]);
break;
}
}
UPDATE : Use an object to refer the index of element would make it far better.
var numbers = [7, 5, 7, 6, 6, 4, 9, 10, 2, 11],
ref = {};
// iterate over the array
for (var i = 0; i < numbers.length; i++) {
// check value already defined or not
if (numbers[i] in ref) {
// if defined then log data and brek loop
console.log("index:", ref[numbers[i]], "value: ", numbers[i]);
break;
}
// define the reference of the index
ref[numbers[i]] = i;
}
Many good answers.. One might also do this job quite functionally and efficiently as follows;
var arr = [2,5,5,2,3,5,1,2,4],
frei = arr.findIndex((e,i,a) => a.slice(i+1).some(n => e === n)); // first repeating element index
console.log(frei)
If might turn out to be efficient since both .findIndex() and .some() functions will terminate as soon as the conditions are met.
You could use two for loops an check every value against each value. If a duplicate value is found, the iteration stops.
This proposal uses a labeled statement for breaking the outer loop.
var numbers = [1, 3, 6, 7, 5, 7, 6, 6, 4, 9, 10, 2, 11],
i, j;
outer: for (i = 0; i < numbers.length - 1; i++) {
for (j = i + 1; j < numbers.length; j++) {
if (numbers[i] === numbers[j]) {
console.log('found', numbers[i], 'at index', i, 'and', j);
break outer;
}
}
}
Move through each item and find if same item is found on different index, if so, it's duplicate and just save it to duplicate variable and break cycle
var numbers = [7, 5, 7, 6, 6, 4, 9, 10, 2, 11];
var duplicate = null;
for (var i = 0; i < numbers.length; i++) {
if (numbers.indexOf(numbers[i]) !== i) {
duplicate = numbers[i];
break; // stop cycle
}
}
console.log(duplicate);
var numbers = [7, 5, 7, 6, 6, 4, 9, 10, 2, 11];
var map = {};
for (var i = 0; i < numbers.length; i++) {
if (map[numbers[i]] !== undefined) {
console.log(map[numbers[i]]);
break;
} else {
map[numbers[i]] = i;
}
}
Okay so let's break this down. What we're doing here is creating a map of numbers to the index at which they first occur. So as we loop through the array of numbers, we check to see if it's in our map of numbers. If it is we've found it and return the value at that key in our map. Otherwise we add the number as a key in our map which points to the index at which it first occurred. The reason we use a map is that it is really fast O(1) so our overall runtime is O(n), which is the fastest you can do this on an unsorted array.
As an alternative, you can use indexOf and lastIndexOf and if values are different, there are multiple repetition and you can break the loop;
function getFirstDuplicate(arr) {
for (var i = 0; i < arr.length; i++) {
if (arr.indexOf(arr[i]) !== arr.lastIndexOf(arr[i]))
return arr[i];
}
}
var arrWithNumbers = [2, 5, 5, 2, 3, 5, 1, 2, 4];
console.log(getFirstDuplicate(arrWithNumbers))
var numbers = [1, 3, 6, 7, 5, 7, 6, 6, 4, 9, 10, 2, 11]
console.log(getFirstDuplicate(numbers))
I have the same task and came up with this, pretty basic solution:
var arr = [7,4,2,4,5,1,6,8,9,4];
var firstIndex = 0;
for(var i = 0; i < arr.length; i++){
for( var j = i+1; j < arr.length; j++){
if(arr[i] == arr[j]){
firstIndex = arr[i];
break;
}
}
}
console.log(firstIndex);
First for loop takes the first element from array (number 7), then the other for loop checks all other elements against it, and so on.
Important here is to define j in second loop as i+1, if not, any element would find it's equal number at the same index and firstIndex would get the value of the last one after all loops are done.
To reduce the time complexity in the aforementioned answers you can go with this solution:
function getFirstRecurringNumber(arrayOfNumbers) {
const hashMap = new Map();
for (let number of arrayOfNumbers) { // Time complexity: O(n)
const numberDuplicatesCount = hashMap.get(number);
if (numberDuplicatesCount) {
hashMap.set(number, numberDuplicatesCount + 1);
continue;
}
hashMap.set(number, 1); // Space complexity: O(n)
}
for (let entry of hashMap.entries()) { // Time complexity: O(i)
if (entry[1] > 1) {
return entry[0];
}
}
}
// Time complexity: O(n + i) instead of O(n^2)
// Space complexity: O(n)
Using the code below, I am able to get just the first '5' that appears in the array. the .some() method stops looping through once it finds a match.
let james = [5, 1, 5, 8, 2, 7, 5, 8, 3, 5];
let onlyOneFives = [];
james.some(item => {
//checking for a condition.
if(james.indexOf(item) === 0) {
//if the condition is met, then it pushes the item to a new array and then
//returns true which stop the loop
onlyOneFives.push(item);
return james.indexOf(item) === 0;
}
})
console.log(onlyOneFives)
Create a function that takes an array with numbers, inside it do the following:
First, instantiate an empty object.
Secondly, make a for loop that iterates trough every element of the array and for each one, add them to the empty object and check if the length of the object has changed, if not, well that means that you added a element that already existed so you can return it:
//Return first recurring number of given array, if there isn't return undefined.
const firstRecurringNumberOf = array =>{
objectOfArray = {};
for (let dynamicIndex = 0; dynamicIndex < array.length; dynamicIndex ++) {
const elementsBeforeAdding = (Object.keys(objectOfArray)).length;0
objectOfArray[array[dynamicIndex]] = array[dynamicIndex]
const elementsAfterAdding = (Object.keys(objectOfArray)).length;
if(elementsBeforeAdding == elementsAfterAdding){ //it means that the element already existed in the object, so it didnt was added & length doesnt change.
return array[dynamicIndex];
}
}
return undefined;
}
console.log(firstRecurringNumberOf([1,2,3,4])); //returns undefined
console.log(firstRecurringNumberOf([1,4,3,4,2,3])); //returns 4
const arr = [1,9,5,2,3,0,0];
const copiedArray = [...arr];
const index = arr.findIndex((element,i) => {
copiedArray.splice(0,1);
return copiedArray.includes(element)
})
console.log(index);
var addIndex = [7, 5, 2, 3, 4, 5, 7,6, 2];
var firstmatch = [];
for (var i = 0; i < addIndex.length; i++) {
if ($.inArray(addIndex[i], firstmatch) > -1) {
return false;
}
firstmatch.push(addIndex[i]);
}

Deleting both values from array if duplicate - JavaScript/jQuery

I have an array here:
var myArr = [1, 1, 2, 5, 5, 7, 8, 9, 9];
Now I want to remove both appearances of a duplicate. So the desired result is not:
var myArr = [1, 2, 5, 7, 8 ,9];
but
var myArr = [2, 7, 8];
Basically I know how to remove duplicates, but not in that that special way. Thats why any help would be really appreciated!
Please note: My array is filled with strings. The numbers here were only used as an example.
jsfiddle for this code:
var myArr = [1, 1, 2, 5, 5, 7, 8, 9, 9];
var newArr = myArr;
var h,i,j;
for(h = 0; h < myArr.length; h++) {
var curItem = myArr[h];
var foundCount = 0;
// search array for item
for(i = 0; i < myArr.length; i++) {
if (myArr[i] == myArr[h])
foundCount++;
}
if(foundCount > 1) {
// remove repeated item from new array
for(j = 0; j < newArr.length; j++) {
if(newArr[j] == curItem) {
newArr.splice(j, 1);
j--;
}
}
}
}
Here's my version
var a = [1, 1, 2, 5, 5, 7, 8, 9, 9];
function removeIfduplicate( arr ) {
var discarded = [];
var good = [];
var test;
while( test = arr.pop() ) {
if( arr.indexOf( test ) > -1 ) {
discarded.push( test );
continue;
} else if( discarded.indexOf( test ) == -1 ) {
good.push( test );
}
}
return good.reverse();
}
x = removeIfduplicate( a );
console.log( x ); //[2, 7, 8]
EDITED with better answer:
var myArr = [1, 1, 2, 5, 5, 7, 8, 9, 9];
function removeDuplicates(arr) {
var i, tmp;
for(i=0; i<arr.length; i++) {
tmp = arr.lastIndexOf(arr[i]);
if(tmp === i) {
//Only one of this number
} else {
//More than one
arr.splice(tmp, 1);
arr.splice(i, 1);
}
}
}
Using Hashmap
create hashmap and count occurencies
filter where hashmap.get(value) === 1 (only unique values)
const myArray = [1, 1, 2, 5, 5, 7, 8, 9, 9];
const map = new Map();
myArray.forEach(v => map.set(v, map.has(v) ? map.get(v)+1 : 1));
myArray.filter(v => map.get(v) === 1);
Old version (slower but valid too)
Heres a short version using Array.filter(). The trick is to first find all values that are NOT uniqe, and then use this array to reject all unique items in the original array.
let myArr = [1, 1, 2, 5, 5, 7, 8, 9, 9];
let duplicateValues = myArr.filter((item, indx, s) => s.indexOf(item) !== indx);
myArr.filter(item => !duplicateValues.includes(item));
// => [2, 7, 8]
Wherever removing duplicates is involved, it's not a bad idea to use a set data structure.
JavaScript doesn't have a native set implementation, but the keys of an object work just as well - and in this case help because then the values can be used to keep track of how often an item appeared in the array:
function removeDuplicates(arr) {
var counts = arr.reduce(function(counts, item) {
counts[item] = (counts[item] || 0) + 1;
return counts;
}, {});
return Object.keys(counts).reduce(function(arr, item) {
if (counts[item] === 1) {
arr.push(item);
}
return arr;
}, []);
}
var myArr = [1, 1, 2, 5, 5, 7, 8, 9, 9];
console.log(removeDuplicates(myArr), myArr);
Check out the example on jsfiddle.
Alternately, you could not use calls to reduce(), and instead use for and for(item in counts) loops:
function removeDuplicates(arr) {
var counts = {};
for(var i=0; i<arr.length; i++) {
var item = arr[i];
counts[item] = (counts[item]||0)+1;
}
var arr = [];
for(item in counts) {
if(counts[item] === 1) {
arr.push(item);
}
}
return arr;
}
Check out the example on jsfiddle.
If it's just alphanumeric, duplicates are case-sensitive, and there can be no more than two of any element, then something like this can work:
var a = [2, 1, "a", 3, 2, "A", "b", 5, 6, 6, "B", "a"],
clean_array = $.map(a.sort(), function (v,i) {
a[i] === a[i+1] && (a[i] = a[i+1] = null);
return a[i];
});
// clean_array = [1,3,5,"A","B","b"]
In this example,we are taking two arrays as function arguments, from this we are going to print only unique values of both arrays hence deleting the values that are present in both arrays.
first i am concatenating both the arrays into one. Then I taking each array value at a time and looping over the array itself searching for its no of occurrence. if no of occurrence(i.e.,count) equal to 1 then we are pushing that element into the result array. Then we can return the result array.
function diffArray(arr1, arr2) {
var newArr = [];
var myArr=arr1.concat(arr2);
var count=0;
for(i=0;i<myArr.length;i++){
for(j=0;j<myArr.length;j++){
if(myArr[j]==myArr[i]){
count++;
}
}
if(count==1){
newArr.push(myArr[i]);
}
count=0;
}
return newArr;
}
EDIT: Here is the jspref http://jsperf.com/deleting-both-values-from-array
http://jsfiddle.net/3u7FK/1/
This is the fastest way to do it in two passes without using any fancy tricks and keeping it flexible. You first spin through and find the count of every occurance and put it into and keyvalue pair. Then spin through it again and filter out the ones where the count was greater than 1. This also has the advanatage of being able to apply other filters than just "greater than 1"; as well as the having the count of occurances if you needed that as well for something else.
This should work with strings as well instead of numbers.
http://jsfiddle.net/mvBY4/1/
var myArr = [1, 1, 2, 5, 5, 7, 8, 9, 9];
var map = new Object();
for(var i = 0; i < myArr.length; i++)
{
if(map[myArr[i]] === undefined)
{
map[myArr[i]] = 1;
}
else
{
map[myArr[i]]++;
}
}
var result = new Array();
for(var i = 0; i < myArr.length; i++)
{
if(map[myArr[i]] > 1)
{
//do nothing
}
else
{
result.push(myArr[i]);
}
}
alert(result);
You can use Set (available in IE 11+) as below
const sourceArray = [1, 2, 3, 4, 5, 5, 6, 6, 7, 7, 8];
const duplicatesRemoved = new Set();
sourceArray.forEach(element => {
if (duplicatesRemoved.has(element)) {
duplicatesRemoved.delete(element)
} else {
duplicatesRemoved.add(element)
}
})
console.log(Array.from(duplicatesRemoved))
N.B. Arrow functions are not supported in older browsers. Use normal function syntax for that instead. However, Array.from can easily be polyfilled for older browsers.
Try it here.

Categories