I have been working on this for a while now and I have no idea why this isn't working. I've read over it a few times and I can't seem to find the problem in my code.
I thought if(arr[i] === item) would check if the current element is equal to the item parameter and if true, return the index.
const lastIndexOf = (arr, item) => {
if(arr.includes(item)){
for(let i = arr.length - 1; i >= 0; i--){
if(arr[i] === item){
return i;
} else if (arr.includes(i) === false){
return Number('-1');
}
}
} else if (!arr.length){
return Number('-1');
} else {
return Number('-1');
}
}
console.log(lastIndexOf([5,5,5,5,0],5));
Remove the else if branch, as it is checking if the array contains the current index, which is nonsensical. Also, just use -1 instead of Number('-1').
const lastIndexOf = (arr, item) => {
if(arr.includes(item)){
for(let i = arr.length - 1; i >= 0; i--){
if(arr[i] === item){
return i;
}
}
return -1;
} else {
return -1;
}
}
console.log(lastIndexOf([5,5,5,5,0],5));
You are currently passing through the array twice, once using Array#includes and once with your for loop, which is suboptimal. You can simply loop over the array backwards once, like you are currently doing, and return -1 at the end of the function, since it will only reach there if the item has not been found.
const lastIndexOf = (arr, item) => {
for(let i = arr.length - 1; i >= 0; i--){
if(arr[i] === item){
return i;
}
}
return -1;
}
console.log(lastIndexOf([5,5,5,5,0],5));
The Array#lastIndexOf method already exists, so there is no need to reinvent the wheel, unless you are trying to make a polyfill.
console.log([5,5,5,5,0].lastIndexOf(5));
The problem is here:
} else if (arr.includes(i) === false){
You're asking if any of the array members equals the current index. Because 4 (your first checked index) is not accounted for in that array, it returns.
Seems like you don't need that else if at all.
const lastIndexOf = (arr, item) => {
if(arr.includes(item)){
for(let i = arr.length - 1; i >= 0; i--){
if(arr[i] === item){
return i;
}
}
} else {
return -1;
}
}
console.log(lastIndexOf([5,5,5,5,0],5));
Also, the last, outer else if and else branches yield the same result, so the else if is extraneous, so I removed it.
And Number('-1') is an unnecessarily roundabout way of returning -1.
And actually, your .includes() check seems redundant. It's going to have to iterate before you iterate. Might as well just do it once.
const lastIndexOf = (arr, item) => {
for(let i = arr.length - 1; i >= 0; i--){
if(arr[i] === item){
return i;
}
}
return -1;
}
console.log(lastIndexOf([5,5,5,5,0],5));
Related
This question already has answers here:
How to compare arrays in JavaScript?
(61 answers)
Closed 3 months ago.
I'm trying to make a function that takes an array as input and a target, and then iterates the array to check if the current index is equal to the target. If so, it will splice the current index from the array.
Everything works fine so far, however when i implement an if statement to check if the index is at the end of the array and then check if the result array is equal to the input array. I really don't know why this is taking me so long it's kind of embarrassing... Here's my code:
let array = ['fox', 'tiger', 'elephant', 'jaguar', 'wolf', 'deer', 'hog', 'dhole', 'leopard', 'eagle', 'bear'];
const splice = (arr, target) => {
//creates empty result array
let result = [];
//iterate through the input array and push each item to the result array
for(let i = 0; i < arr.length; i++) {
result.push(arr[i]);
}
let j = 0;
//iterate through result array
while(j < result.length) {
if (result[j] === target) {
result.splice(j, 1);
}
//i have tried this multiple times with the if statement in and out of the loop
if (j === result.length && result === arr) {
//throw new Error(`${target} was not found in the array`);
console.log({result, arr, j});
return 'equal';
} else if (j === result.length && result !== arr ) {
console.log({result, arr, j});
return 'different';
}
j++;
}
};
//should return 'equal' but returns 'different'
console.log(splice(array, 'turtle'));
//should return 'different' but returns undefined
console.log(splice(array, 'bear'));
Hope this help
const splice = (arr, target) => {
//creates empty result array
let result = [];
//iterate through the input array and push each item to the result array
for(let i = 0; i < arr.length; i++) {
result.push(arr[i]);
}
let j = 0;
//iterate through result array
while(j < result.length) {
if (result[j] === target) {
result.splice(j, 1);
/* since you modified the length of result array here,
u can simply check the length of result array
with the original array to see if there's a different */
}
// result === arr will always resolve to fasle as they are not the same object, so check the length instead
if (j === result.length && result.length !== arr.length) {
//throw new Error(`${target} was not found in the array`);
console.log({result, arr, j});
return 'equal';
} else if (j === result.length && result.length === arr.length ) {
console.log({result, arr, j});
return 'different';
}
j++;
}
// a better way of doing it is to move the if check outside of while loop to avoid it run multiple time
if (result.length !== arr.length) { // different length, that mean we found the target and the result array got modified
console.log({result, arr, j});
return 'equal';
} else {
console.log({result, arr, j});
return 'different';
}
};
Here you can use this logic to compare two arrays are same or not :
let arr1 = [1, 2, 3, -2, null];
let arr2 = [1, 2, 3, -2, null];
let bool = true;
let i;
for (i = 0; i < arr1.length; i++) {
if (arr1[i] !== arr2[i]) {
bool = false;
break;
}
}
if (arr1[i] === arr2[i]) bool = true;
if (arr1[i] !== arr2[i] || arr1.length !== arr2.length) bool = false;
if (bool) console.log("same");
else console.log("different");
As others told you in comments, since arrays are object in JavaScript, you cannot compare them with a simple ===.
To compare 2 arrays, first, you have to decide what do you means by arr1 === arr2.
For example:
does [A,C,B] concider equals to [A,B,C]?
how about [A,B,C, ]?
Lets say you need the two arrays to have...
1.) same length,
2.) index value must matches.
you can do something like this:
const arr1 = [1,2,3,"A"];
const arr2 = [1,2,3,"A"];
function compareArr(A,B) {
return (A.length === B.length) && A.every((v,i) => B[i] === v)
}
console.log(compareArr(arr1,arr2))
i want to check the array for the same datatypes. i found other solutions here but i want to do it with for loop and if conditonals.
Can someone please explain, why my code is not working:
thank you very much!
function sameDataType(array){
const helper = []
for(let i = 0; i < array.length; i++){
let dataType0 = typeof(array[i])
let dataType1 = typeof(array[i+1])
if(dataType0 === dataType1){
helper.push(1)
} else {
helper.push("not")
}
}
for(let j = 0; j < helper.length; j++){
if(helper[j] === helper[j+1]){
return "same"
} else {
return "different"
}
}
}
console.log(sameDataType([1, 1, "string"]))
Please use Array.map and Array.filter function.
First you get array of types.
And then filter it with removing the duplicated values.
Then check the length.
Like this.
function sameDataType1(array){
return array.map(val => typeof val).filter((val, index, self) => self.indexOf(val) === index).length === 1 ? "same" : "different";
}
console.log(sameDataType1([1, 1, "string"]))
Will try to improve upon your code only.
Firstly check if the array even has enough elements. If only one element, simply return same.
Then make sure you run your loop till the correct indices. Notice you have i+1 & j+1 in your code. You do arr[arr.length+1], you are getting undefined.
Also check for the condition when you have only two elements.
function sameDataType(array){
if(array.length > 1 ) {
const helper = []
for(let i = 0; i < array.length - 1; i++){
let dataType0 = typeof(array[i])
let dataType1 = typeof(array[i+1])
if(dataType0 === dataType1){
helper.push(1)
} else {
helper.push("not")
}
}
if(helper.length === 1 ){
if(helper[0] === 1) return "same";
return "different";
}
for(let j = 0; j < helper.length-1; j++){
if(helper[j] === 1 && helper[j] === helper[j+1]){
return "same"
} else {
return "different"
}
}
}
return "same";
}
console.log(sameDataType([1, 1 , "string"]))
console.log(sameDataType([1, "string:" ]))
console.log(sameDataType(["string", "string" , "string"]))
So the question reads:
Given an array a that contains only numbers in the range from 1 to a.length, find the first duplicate number for which the second occurrence has the minimal index. In other words, if there are more than 1 duplicated numbers, return the number for which the second occurrence has a smaller index than the second occurrence of the other number does. If there are no such elements, return -1.
Write a solution with O(n) time complexity and O(1) additional space complexity.
I have a solution, but apparently it's not fast enough and stalls when there are over a thousand items in the array.
This is what I have:
function firstDuplicate(arr) {
let dictionary = {};
for(let i = 0, ii = arr.length; i < ii; i++) {
for(let z = i+1, zz = arr.length; z < zz; z++) {
if(arr[i] === arr[z]) {
if(dictionary.hasOwnProperty(arr[i])) {
if(dictionary[arr[i]] !== 0 && dictionary[arr[i]] > z) {
dictionary[i] = z;
}
} else {
dictionary[arr[i]] = z;
}
}
}
}
let answer = [];
for(key in dictionary) {
// [array number, position];
answer.push([key, dictionary[key]]);
};
if(answer.length > 0) {
return Number(answer.sort((a, b) => {
return a[1]-b[1];
})[0][0]);
}
return -1;
}
I think converting the object into an array and then sorting the array after the answers are complete slows down the whole function. Using built in JS methods like forEach, map and sort (like I did above), slows the code/function down even more. There is obviously a better and more accurate way to do this, so I'm asking for some JS masterminds to help me out on this.
you can keep adding numbers to a dictionary as keys with values as their index, and as soon as you find a repeating key in the dictionary return its value. This will be O(n) time complexity and O(n) space complexity.
function firstDuplicate(arr) {
var dictionary = {};
for(var i = 0; i < arr.length; i++) {
if(dictionary[arr[i]] !== undefined)
return arr[i];
else
dictionary[arr[i]] = i;
}
return -1;
}
console.log(firstDuplicate([2, 3, 3, 1, 5, 2]));
Since the numbers are between 1 to arr.length you can iterate on the array. For each arr[i] use arr[i] as index and make the element present and arr[arr[i]] negative, then the first arr[arr[i]] negative return arr[i]. This give O(1) space complexity and O(n) time complexity you can do this:
function firstDuplicate(arr) {
for(var i = 0; i < arr.length; i++) {
if(arr[Math.abs(arr[i])] < 0)
return Math.abs(arr[i]);
else
arr[Math.abs(arr[i])] = 0 - arr[Math.abs(arr[i])];
}
return -1;
}
console.log(firstDuplicate([2, 3, 3, 1, 5, 2]));
function firstDuplicate(arr) {
for(var i = 0; i < arr.length; i++) {
var num = Math.abs(arr[i]);
if(arr[num] < 0)
return num;
arr[num] = - arr[num];
}
return -1;
}
console.log(firstDuplicate([2,2,3,1,2]));
function firstDuplicate(arr) {
var numMap = {};
for (var i = 0; i < arr.length; i++) {
if (numMap[arr[i]]) {
return arr[i];
}
numMap[arr[i]] = true;
}
return -1;
}
Answer mentioned by #dij is great, but will fail for [2,2] or [2,3,3],
a little change
for input [2,2], i=0 we get a[ Math.abs[a[0] ] = a[2] = undefined
so we remove 1 from a[ Math.abs[a[0] -1 ] this will work now
function firstDuplicate(arr) {
for(var i = 0; i < arr.length; i++) {
if(arr[Math.abs(arr[i])-1] < 0)
return Math.abs(arr[i]);
else
arr[Math.abs(arr[i])-1] = 0 - arr[Math.abs(arr[i])-1];
}
return -1;
}
Please try the code below:
function getCountOccurence(A) {
let result = [];
A.forEach(elem => {
if (result.length > 0) {
let isOccure = false;
result.some((element) => {
if (element.element == elem) {
element.count++;
isOccure = true;
}
});
if (!isOccure) {
result.push({element: elem, count: 1});
}
} else {
result.push({element: elem, count: 1});
}
});
return result;
}
function getFirstRepeatingElement(A) {
let array = getCountOccurence(A);
array.some((element)=> {
if (element.count > 1) {
result = element.element;
return true;
}
});
return result;
}
Why is this recursive countOccurence function not working? this has a subroutine. is there a way to do it without a subroutine? it seems in javascript you have to have a closure (subroutine function) for the counter variable, otherwise it gets rewritten every time!
function numOccurencesRecursive(arr, val) {
//base case. check it if it only has a length of 1
var count = 0;
function doCount(arr, val) {
if (arr[0] === val) {
count++;
} else {
count += doCount(arr.slice(1), val)
}
return count;
}
return doCount(arr, val);
}
console.log(numOccurencesRecursive([2, 7, 4, 4, 1, 4], 4)); // should return 3 but returns 1
I think the problem is that you were thinking iteratively but used a recursive approach.
The iterative approach has a global variable which may be updated at each step:
function numOccurencesIterative(arr, val) {
var count = 0;
for(var i=0; i<arr.length; ++i) if(arr[i] === val) ++count;
return count;
}
However, when using recursive approaches, better avoid global variables.
function numOccurencesRecursive(arr, val) {
if(!arr.length) return 0;
return (arr[0] === val) + numOccurencesRecursive(arr.slice(1), val);
}
This should definitely do with all the nests with recursion:
function countItems(arr, item) {
var count = 0;
for (var i=0; i<arr.length; i++){
if (typeof(arr[i]) == typeof([])){
count += countItems(arr[i], item);
}
else{
if(typeof(arr[i]) != typeof([])){
if (arr[i] === item){
++count;
}
}
}
}
return count;
}
doCount stops recursing once it finds a match; hence, it will never find more than 1 match to count.
So, what you are doing is that you are incrementing the count only when you find the value, and when you do find it, your recursive function ends, but its the other way around, which means you have to count for unfound elements in the array and if you find something, increment it and then if the array is empty, return the count.
Code:
function numOccurencesRecursive(arr, val) {
//base case. check it if it only has a length of 1
var count = 0;
function doCount(arr, val) {
if (arr[0] === val) {
count++;
} else if (!arr.length) {
return count;
}
return doCount(arr.slice(1), val);
}
return doCount(arr, val);
}
console.log(numOccurencesRecursive([2, 7, 4, 4, 1, 4], 4)); // should return 3 but returns 1
I have an array
var arr = [{"id":"1","name":"One"},{"id":"2","name":"Two"}]
I push to the array
arr.push(X)
But how can I remove for example {"id":"1","name":"One"} from this array by name?
In plain javascript, you have to search through the array looking for a name match in each object and then remove that object:
function removeFromArrayByName(arr, name) {
for (var i = 0; i < arr.length; i++) {
if (arr[i].name === name) {
arr.splice(i, 1);
return;
}
}
}
Or if there might be more than one match and you want to remove all the matches there are, you can do this (does a backward traversal and doesn't return when it finds a match):
function removeFromArrayByName(arr, name) {
for (var i = arr.length - 1; i >= 0; i--) {
if (arr[i].name === name) {
arr.splice(i, 1);
}
}
}
Or, you could even make it more generic where you pass in the property name to search too:
function removeFromArrayByName(arr, prop, val) {
for (var i = arr.length - 1; i >= 0; i--) {
if (arr[i][prop] === val) {
arr.splice(i, 1);
}
}
}
The question is for plain js but if you use jquery, you can write a function like this:
function removeByName(arr, key){
return $.grep(arr, function (n,i) {
return n.name != key;
});
}
In your case, I will call removeByName(arr,'One');