!== Comparison Operator Should Be True but Isn't - javascript

function nonUniqueElements(data) {
var duplicates = [];
var compArr = data;
for (var i = 0; i < data.length; i++) {
for (var j = 0; j < compArr.length; j++) {
console.log('Comparing ' + data[i] + ' to ' + compArr[j]);
if (data[i] === compArr[j]) {
console.log('Found match first pass');
console.log(data.indexOf(i), compArr.indexOf(j));
if (data.indexOf(i) !== compArr.indexOf(j)) {
console.log('Also passes second pass')
console.log('Pushing ' + data[i] + ' to new array')
duplicates.push(data[i]);
console.log(duplicates);
}
}
}
console.log('End of run through');
}
return (duplicates);
}
console.log(nonUniqueElements([5, 5, 5, 5]));
I'm trying to return all non-unique values in an array. I've duplicated the array and am running a nested loop to compare the copy against the original.
When it finds a match (in this case every time), there's a second check to ensure that only values at a different index are pushed to a new array.
I've put some console.log()s to help me step through the program. Even when console.log(data.indexOf(i), compArr.indexOf(j)) is printing different values, the block of code in the if (data.indexOf(i) !== compArr.indexOf(j)) statement isn't running.
Any ideas?

In JS, the indexOf() method returns the position of the first occurrence of a specified value in a string/array. You can tell it's wrong since in the console.log you always get the value -1.
What you need to compare is data[i] and compArr[j].

if (data.indexOf(i) !== compArr.indexOf(j)) {
Why are you comparing indexes of i and j ?
i and j are indexes themselves, not elements.
Don't you mean
if (data[i] !== compArr[j]) {

You are trying to compare two true values.
Take a look at the definition of indexOf is:
Array.indexOf: method returns the first index at which a given element can be found in the array, or -1 if it is not present.
String.indexOf: method returns the index within the calling String object of the first occurrence of the specified value, starting the search at fromIndex. Returns -1 if the value is not found.
So, in your condition if (data.indexOf(i) !== compArr.indexOf(j)) you're comparing the index of i and j that holds the numbers of 0 to 3 (data.length). In your Array, all the values have been set to 5 witch is the reason that you get -1 in return of indexOf, [5,5,5,5].indexOf(0) === -1.
If you're trying to compare the values in data Array you have to compare the values not index of values. Like this: if (data[i] !== compArr[j]).
At the end I recommend you to read this document Truthy and Falsy: When All is Not Equal in JavaScript

It might be simpler to use Array.reduce...
var array = [1,2,3,4,5,6,4,5,66,44,66]
var result = array.reduce((prev,value) => {
if ( prev.exists[value] ) { prev.dupes[value] = true; }
prev.exists[value] = true;
return prev;
},{ exists: {}, dupes: {} })
var duplicates = Object.keys(result.dupes);
console.log('duplicates',duplicates);
var filterDupes = array.filter(value => result.dupes[value])
console.log('fitlerDupes',filterDupes);
var mapDupes = array.map(value => result.dupes[value] ? value : null)
console.log('mapDupes',mapDupes);
for ( var i = 0; i < array.length; i ++ ) {
if ( !result.dupes[array[i]] ) { array.splice(i,1); i--; }
}
console.log('Original Array',array);

Related

Write a function getDuplicates

Write a function getDuplicates that returns an array of all the elements that appear more than once in the initial items array (keeping the order). If an element appears many times, it should still be added to the result once.
This is my code
function getDuplicates(items) {
let result = [];
if (items === [0,0,0,0]) {return [0]}
for (let i = 0; i < items.length; i++) {
for (let j = i + 1; j < items.length; j++) {
if (items[i] === items[j]) {
result.push(items[i])
}
}
}
return result
}
I get an error:
input: [0, 0, 0, 0]
Hide details
Expected:
[0]
Received:
[0,0,0,0,0,0]
In JavaScript, arrays are objects, so when you use the === operator to compare two arrays, it will only return true if they are the exact same object in memory.
Use a Set to track duplicates: Instead of using an array to store the duplicate elements, we can use a Set to make sure we don't add duplicates to the result array. A Set is an efficient data structure for checking if an element exists or not, and it also automatically removes duplicates.
Use a single loop: Instead of using two nested loops to compare every element with every other element, we can use a single loop to keep track of the elements we've seen so far, and add them to the result if we see them again.
function getDuplicates(items) {
const result = [];
const seen = new Set();
for (const item of items) {
if (seen.has(item) && !result.includes(item)) {
result.push(item);
} else {
seen.add(item);
}
}
return result;
}
console.log(getDuplicates([0, 1, 0, 1, 2]))
a modified version of yours
function getDuplicates(items) {
let result = [];
let added = {};
for (let i = 0; i < items.length; i++) {
if (!added[items[i]] && items.indexOf(items[i], i + 1) !== -1) {
result.push(items[i]);
added[items[i]] = true;
}
}
return result;
}
console.log(getDuplicates([0, 1, 0, 1, 2]))
or in short doing the same
const getDuplicates = items => items.filter((item, index) => items.indexOf(item) !== index && items.lastIndexOf(item) === index);
console.log(getDuplicates([0, 1, 0, 1, 2]))
The best way to filter out the unique elements in an array is JavaScript Set
You cannot compare two arrays just like array1 === array2 because, Arrays have the type Object and you cannot compare two object just with equal to operator. Objects are not compared based on their values but based on the references of the variables. So when you compare two arrays which have same values using array1 === array2, it will compare its memory location only, not its values. So it will be only false.
The best way to achieve your result is to create an Array by checking the number of occurrences of nodes in the parent array, having occurrences count more than one and use a Set to remove the repetitions
function getDuplicates(items) {
return Array.from(new Set(items.filter(node => items.filter(x => node === x).length > 1)))
}
console.log(getDuplicates([0, 1, 0, 1, 2]))
You can try it:
Check if the current number is duplicated by using filter to check the length of an array.
Check if the result array contains duplicates.
function getDuplicates(items) {
let result = [];
for (let i = 0; i < items.length; i++) {
if ((items.filter(item => item == items[i])).length > 1 && !result.includes(items[i])) {
result.push(items[i]);
}
}
return result;
}
console.log(getDuplicates([0, 0, 0, 0]));
So. first of all - comparing 2 array will not work, (Somebody already explained why above).
Your code doesn't work because of if statement. You're checking if an array doesn't have any value except 0.
Try summing all numbers in the array and check if it's 0.
if(arr.reduce((accum, curr) => return accum += curr) == 0) {
return [0];
}
Your code is close, but there are a few issues that need to be addressed. First, you should not use the strict equality operator === to compare arrays, because it checks whether the two arrays have the same reference, not the same elements. Instead, you can use the JSON.stringify() method to compare the string representations of the arrays.
Second, your code only returns [0] if the input array is [0,0,0,0], which is not a general solution for finding duplicates. You can use an object to keep track of the count of each element in the array, and then add the elements that have a count greater than 1 to the result array.
Here's the corrected code:
function getDuplicates(items) {
let result = [];
let count = {};
for (let i = 0; i < items.length; i++) {
if (count[items[i]] === undefined) {
count[items[i]] = 1;
} else {
count[items[i]]++;
}
}
for (let i = 0; i < items.length; i++) {
if (count[items[i]] > 1 && result.indexOf(items[i]) === -1) {
result.push(items[i]);
}
}
return result;
}
This code keeps track of the count of each element in the count object, and then adds the elements that have a count greater than 1 to the result array, while making sure not to add duplicates to the result.

Finding first occurrence of each digit in an array

Taking each four digit number of an array in turn, return the number that you are on when all of the digits 0-9 have been discovered. If not all of the digits can be found, return "Missing digits!"
I've tried to loop through then set a conditional if (i != i+1) push into new array this just gave me the array, it's apparent my logic is wrong. could anyone help me out
For example calling this function with
arr = findAllDigits([5175, 4538, 2926, 5057, 6401, 4376, 2280, 6137, 8798, 9083])
the code should return 5057.
While calling
arr = findAllDigits([4883, 3876, 7769, 9846, 9546, 9634, 9696, 2832, 6822, 6868])
should return "missing numbers"
function findAllDigits(arr) {
newArr = [];
for (let i = 0; i < arr.length; i++) {
if (arr[i] != arr[i + 1]) newArr.push(arr[i]);
console.log(newArr);
}
}
Do I need to split because it is taking everything before the comma as
one number, then iterate over?
You can use Set here
Loop over the array and then create a set, You have to return the current number if set size becomes 10 because you need to check 0-9
function findAllDigits(arr) {
const set = new Set();
for (let n of arr) {
String(n)
.split("")
.forEach((c) => set.add(c));
if (set.size === 10) return n;
}
return "Missing digits!";
}
const arr1 = [5175, 4538, 2926, 5057, 6401, 4376, 2280, 6137, 8798, 9083];
const arr2 = [4883, 3876, 7769, 9846, 9546, 9634, 9696, 2832, 6822, 6868];
console.log(findAllDigits(arr1));
console.log(findAllDigits(arr2));
Your for loop is only checking to see if the array entry is equal to the next one. You need to split up the digits inside each entry and store them individually:
function findAllDigits(arr) {
newArr = [];
for (let i = 0; i < arr.length; i++) {
// now iterate the individual digits
const entryAsString = arr[i].toString();
for (let j = 0; j < entryAsString.length; j++) {
// if we haven't seen the digit before, add it to the array
if(!newArr.includes(j) {
newArr.push(j);
}
}
// we know we have all digits when newArr is 10 entries long
if (newArr.length) {
console.log(arr[i]);
// you can also return this value here
}
}
}
One more solution:
const arr1 = [5175, 4538, 2926, 5057, 6401, 4376, 2280, 6137, 8798, 9083];
const arr2 = [4883, 3876, 7769, 9846, 9546, 9634, 9696, 2832, 6822, 6868];
const findAllDigits = (arr) => {
// Declare new Set: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
const digits = new Set();
// return the first item from array that fits the condition,
// find() method: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
return arr.find((curr) => (
// String(5175) -> '5175' : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String
// [...'5175'] -> ['5','1','7','5'] : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
// .forEach(digits.add, digits) - forEach with callback function and context : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
// comma operator lets get rid of return : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator
[...String(curr)].forEach(digits.add, digits),
// condition - is find() method need to return an item
(digits.size === 10)
// if returned value is not undefined or null return finded number oterwise error string
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator
)) ?? "Missing digits!";
};
console.log(findAllDigits(arr1)); //5057
console.log(findAllDigits(arr2)); //Missing digits!

DailyCodingProblem, find pair in array that matches a given value

I'm fairly new to coding and enlisted for the daily coding problem mailing list and got this question:
Given a list of numbers and a number k, return whether any two numbers
from the list add up to k.
My solution (after some stackoverflow digging) looks like this;
function problemOne_Solve()
{
const k = 17;
const values = [11, 15, 3, 8, 2];
for (i=0; i < values.length; i++) {
if ( values.find( (sum) => { return k-values[i] === sum} ) ) return true;
}
return false;
}
I'm wondering why it works. To me it looks like the part with the fat-arrow function closes the brackets inside the if statements conditional logic. And there is no such brackets after the if statement, which I thought was required.
I was also wondering how i would go about outputting the pair or pairs that sums up to "k," to build further on the solution. I would like to be able to display the pairs on the page for example.
.find takes a callback, which is invoked for every item in the array (or, up until a match is found). The first argument to the callback is the item being iterated over. If a match is found (if the return value from the callback was truthy for any element), the .find returns the item that resulted in a truthy return value.
So, on the first i = 0 iteration, and values[i] is 11, (sum) => { return k-values[i] === sum} will first check whether 17 - 11 === 11, and then whether 17 - 11 === 15, and then whether 17 - 11 = 3, etc.
This condition will generally be fulfilled if two numbers in the array add up to the k, but the algorithm is buggy. For example, an array composed of [1] will check the 1 against itself on the first iteration, adding up to 2:
function problemOne_Solve() {
const k = 2;
const values = [1];
for (i=0; i < values.length; i++) {
if ( values.find( (sum) => { return k-values[i] === sum} ) ) return true;
}
return false;
}
console.log(problemOne_Solve());
That is wrong. Another problem is that .find returns the found value. But, if the array is an array of numbers, the found value may be 0, and 0 is falsey. So the below example should return true because two elements sum up to 0 (0 and 0), but it returns false:
function problemOne_Solve() {
const k = 0;
const values = [0, 0];
for (i=0; i < values.length; i++) {
if ( values.find( (sum) => { return k-values[i] === sum} ) ) return true;
}
return false;
}
console.log(problemOne_Solve());
To get it right and decrease the computational complexity from O(n ^ 2) to O(n), iterate over the array once. Create an object whose keys are the numbers being iterated over, and on each iteration, check to see if a key of target - currNum exists on the object (where target is the target sum, and currNum is the current number from the array):
function problemOne_Solve() {
const target = 17;
const values = [11, 15, 3, 8, 2];
const obj = {};
for (const currNum of values) {
if (obj.hasOwnProperty(target - currNum)) {
return true;
}
obj[currNum] = true;
}
return false;
}
console.log(problemOne_Solve());
I was also wondering how i would go about outputting the pair or pairs that sums up to "k," to build further on the solution. I would like to be able to display the pairs on the page for example.
Instead of returning immediately when a match is found, push to an array and then return that array at the end of the function. Also, instead of setting the object values to true (or false), set them to the number of occurrences the number has been found so far (and decrement the matching number when a match is found):
function problemOne_Solve() {
const target = 17;
const values = [11, 15, 3, 8, 2, 17, 0, 0, 17];
const obj = {};
const matches = [];
for (const currNum of values) {
const otherNum = target - currNum;
if (obj[otherNum]) {
obj[otherNum]--;
matches.push([currNum, otherNum]);
}
obj[currNum] = (obj[currNum] || 0) + 1;
}
return matches;
}
console.log(problemOne_Solve());
And there is no such brackets after the if statement, which I thought was required.
Brackets are not required when there's a single statement after an if (or else if or else), eg:
if (true) console.log('true');
else console.log('this will not log');
And there is no such brackets after the if statement, which I thought was required.
If there is only one statement after if else the brackets becomes optional. Ideally you shouldn't write the if block is one line to make your code clean
As you are a beginner I would recommend you to use simple for loops instead of these fancy methods like find.
You can do that in following steps:
Its clear that you need sum of each element with every other element of array. So you will need a nested loop structure
The outer loop or main loop starts from 0 and loop till end of array.
You need to create a inner loop or nested loop which starts from index after the current index.
In the each iteration of nested loop you need to check if the sum of two elements is equal to requiredSum or not.
function pairWithSum(givenArray, requiredSum){
for(let i = 0; i < givenArray.length; i++){
for(let j = i + 1; j < givenArray.length; j++){
let sum = givenArray[i] + givenArray[j];
if(sum === requiredSum){
return [givenArray[i], givenArray[j]];
}
}
}
return false
}
console.log(pairWithSum([1, 4, 5, 8], 12));
console.log(pairWithSum([1, 4, 5, 8], 15));
I'm wondering why it works
That is because, if expects an expression/ statement to validate.
values.find( (sum) => { return k-values[i] === sum} )
This is a statement and it will be evaluated before and its output will be passed to if for condition.
Now Array.find has a return type: T|<null> where T is any value array is made of. So in second iteration, when values[i] refers to 15, it will return 2.
Now in JS, 2 is a truthy value and hence it goes inside if block. Foe more reference, check All falsey values in JavaScript. Any value that is not in this list will be considered as true.
My Javascript solution using JS object. This solution memories the elements when we go through the array which can be memory expensive. But the complexity will stay as O(n).
const checkTwoSum = (arr, sum) => {
const obj = {};
const found = arr?.find(item => {
const target = sum - item;
if (obj[target]) return true;
else {
obj[item] = 1;
}
});
return !!(found || found === 0);
}

How to add a string to an array and return the string

Build a function forLoop. It takes an array as an argument. Start counting from 0, and, using a for loop, add a string to the array 25 times. But not just any string. If your i value is 1, add the string "I am 1 strange loop."; if your i value is anything else, add the string "I am ${i} strange loops.". (Remember flow control with if and else? And how do we interpolate i?) Then return the array.
Learning online and am having trouble understanding what is needed to return the array with the string added to it 25 times?
function forLoop(array) {
for (let i = 0; i < 25; i++) {
if (i === 1) {
console.log(`${array} I am 1 strange loop.`);
} else {
console.log(`${array}I am ${i} strange loops.`);
}
}
}
forLoop(array);
adds `"I am ${i} strange loop${i === 0 ? '' : 's'}."` to an array 25 times:
TypeError: Cannot read property 'slice' of undefined
You're close. You simply need to push the string to the array, and then return the array at the end.
function forLoop(arr) {
for (let i = 0; i < 25; i++) {
if (i === 1) {
// Use `push` to add the string to the array
arr.push(`I am 1 strange loop.`);
} else {
arr.push(`I am ${i} strange loops.`);
}
}
// Return your array
return arr;
}
// Create the array and pass it into the function
const arr = [];
// `out` captures the returned array
const out = forLoop(arr);
console.log(out);
You were almost there. Small updates done and posted below
function forLoop(array) {
for (let i = 1; i <= 25; i++) {
array.push(`I am ${i} strange ${i == 1 ? 'loop' : 'loops'}.`)
}
return array;
}
const result = forLoop([]);
console.log(result);
function forLoop(array: string[]) {
for (let i = 0; i < 25; i++) {
var messsage= 'I am '+i+' strange loop' + (i>0 ? 's.':'.');
array.push (messsage);
console.log(array[i])
}
}
const array:string[]=[];
forLoop(array);
console.log(array.length)
jsfiddle Link

Comparing arrays in javascript where order doesn't matter

I am learning Javascript, and I saw a function on SO for comparing arrays to check if they are same. However, my current function returns false if the two arrays are [string1,string2] & [string2,string1]. Basically, the two positions are interchanged. The code is as follows:
function _compareArrays(arr1,arr2){
var result = arr1 != null && arr2 != null && arr1.length == arr2.length && arr1.every(function(element) {
return arr2.indexOf(element);
});
return result ;
}
However, I want these two arrays to be returned as same. So, I changed .every to .indexOf() and it seemed to work. But, I have a doubt, how exactly is the counter getting incremented here to make sure the comparison is being done for every element?
I mean, like, in C++, we do,
for (int i = 0; i < 10; i++)
if (arr1[i] == arr2[i]
cout<<"Elements are same\n";
Here, I have an explicit i++ which increments the counter. How does it happen in the above function?
Thanks!
Convert the array into an object instead. Convert array values into keys and their respective count as their value. This is more performant as you iterate over the arrays only once.
function compare(a, b) {
if (a.length !== b.length) {
return false;
}
let set = {};
a.forEach((i) => {
if (set[i] !== undefined) {
set[i]++;
} else {
set[i] = 1;
}
});
let difference = b.every((i) => {
if (set[i] === undefined) {
return false;
} else {
set[i]--;
if (set[i] === 0) {
delete set[i];
}
return true;
}
});
return Object.keys(set) == 0 && difference;
}
The first loop on the first array initialises the the set (object), the second loop on the second array subtracts the count and removes the keys when the count hits 0. If a key is not found or if the set is not empty at the end of the procedure, then the arrays are not similar.
Your current has these issues:
It will return true for these 2 arrays (I hope that you understand that this is not specific to these 2): [1, 2, 2], [1,1,2]. This problem is why I set indices to undefined after a match in my solution below.
indexOf returns -1 for element's it cannot find, and any number >= 0 if it can find the element, -1 is truthy, so if an element cannot be found, your comparison will return true, and 0 is falsy, so if an element is located in the first index of the second array, your method will return false (which means the whole thing will become false, because of every...). So, you should add a ~ before the result of indexOf call: ~arr2.indexOf(element).
See this
MDN page on the Bitwise Not operator (~) and how it solves the
indexOf problem I mentioned.
I also recommend that you take a look at this answer of mine on truthy/falsy values and how they interact with && and ||.
So Try this out (it's mostly your example, except there is no indexOf used and I have fixed problem #2):
function _compareArrays(arr1,arr2){
if(!(arr1 != null && arr2 != null && arr1.length == arr2.length)) {
return false;
}
/* copy the arrays so that the original arrays are not affected when we set the indices to "undefined" */
arr1 = [].concat(arr1);
arr2 = [].concat(arr2);
return arr1.every(function(element, index) {
return arr2.some(function(e, i) {
return e === element && (arr2[i] = undefined, true);
});
});
}
var x = ["str", "boo", "str"];
var y = ["boo", "str", "str"];
var z = ["abc", "def", "ghi"]
console.log(_compareArrays(x, y));
console.log(_compareArrays(x, z));
console.log(_compareArrays(z, z));
It won't work if the array has any undefined elements, though.
So the fastest way would be to sort both arrays, then compare each one element by element. This requires 2n * log(n) + n time rather than n2 time.
function compareArrays(arr1, arr2){
if(arr1.length !== arr2.length) return false;
// implement custom sort if necessary
arr1.sort();
arr2.sort();
// use normal for loop so we can return immediately if not equal
for(let i=0; i<arr1.length; i++){
if(arr1[i] !== arr2[i]) return false;
}
return true;
}

Categories

Resources