I am writing a function that returns the longest string in the given array. If the array is empty, it should return an empty string (""). If the array contains no strings; it should return an empty string.
function longestWord(arr) {
var filtered = arr.filter(function(el) { return typeof el == 'number' });
if (filtered.length > 0) {
return Math.min.apply(Math, filtered);
} else {
return 0;
}
}
var output = longestWord([3, 'word', 5, 'up', 3, 1]);
console.log(output); // --> must be 'word'
Right now my codes doesnt pull the word instead it pulls out the number. Any idea what am I missing?
Let's walk through your code.
The first line of your longestWord function:
var filtered = arr.filter(function(el) { return typeof el == 'number' });
will filter the input array based on typeof el === 'number', which will return an array containing only the elements of the input array which are type of === number.
Since the goal is to find the longest word, this should probably be changed to:
var filtered = arr.filter(function(el) { return typeof el === 'string' });
which will return an array of the strings in the input array.
Next, there's a check to see if the filtered array is empty. If the array is empty, you return 0. Your instructions say that if the array is empty, or if the array contains no strings, it should return an empty string. So we should change this to:
return "";
If the array is not empty, or contains strings, Math.min.apply(Math, filtered) is returned. This statement would return the minimum value of an array, so probably not what you want. After all, the goal is to return the longest string.
To do this we can use a variety of methods, here's one:
filtered.reduce(function(a, b) { return a.length > b.length ? a : b })
This statement uses the reduce() method to step through the array and return the longest item.
Putting it all together we get:
function longestWord(arr) {
var filtered = arr.filter(function(el) { return typeof el === 'string' });
if (filtered.length > 0) {
return filtered.reduce(function(a, b) { return a.length >= b.length ? a : b });
} else {
return "";
}
}
console.log(longestWord([3, 'word', 5, 'up', 3, 'testing', 1]));
console.log(longestWord([]));
console.log(longestWord([1, 2, 3, 4, 5]))
console.log(longestWord(['some', 'long', 'four', 'char', 'strs']))
This isn't the most efficient code. For that, seek other answers, especially those that use reduce, however I do find it more readable and thus easier to maintain:
function longestWord(arr) {
var filtered = arr.filter(el => typeof el === 'string')
.sort((a,b) => a.length > b.length ? -1 : 1 );
if (filtered.length)
return filtered[0];
return null;
}
var output = longestWord([3, 'word', 5, 'up', 3, 1]);
console.log(output); // --> must be 'word'
But what to do when two strings are the same length?
I assume the filter meant to be for "string"
Once you have the filtered array, you can simply use reduce to get the longest word
function longestWord(arr) {
return Array.isArray(arr) ?
arr
.filter(el => typeof el == 'string' )
.reduce((a,b) => b.length > a.length ? b : a) : '';
}
console.log(longestWord([3, 'word', 5, 'up', 3, 1, 'blah']));
Even shorter code
var longestWord = (arr) => Array.isArray(arr) ? arr.reduce((a,b) => (typeof b == 'string' && b.length > a.length) ? b : a, '') : '';
const longestWord = arr =>
arr.reduce((result, str) =>
typeof str == 'string' && result.length < str.length
? str
: result, '')
As all other answers are using filter(), reduce() and all that new and fancy methods, I'm gonna answer with the do-it-yourself method (i.e. the old fashion way).
function longestWord(arr) {
if ( ! ( typeof arr === 'array' ) ) {
console.log("That's not an array!");
return '';
}
var longest = ''; // By default, the longest word is the empty string
// Linear search
for ( var i = 0, length = arr.length; i < length; i++ ) {
var el = arr[i];
if ( typeof el === 'string' && el.length > longest.length ) {
// Words STRICTLY GREATER than the last found word.
// This way, only the first word (if two lengths match) will be considered.
longest = el;
}
}
return longest;
}
I know, this is probably NOT what you want since you're already using filtered(), but it works.
Related
I am trying to compare two arrays( containing 3 integers) and return a hint message array that conform to the logic
-Push “Almost” when 1 digit and position match in array
-push “not quite” when 1 digit matches but different position
-push “incorrect “ when no digits match
push “correct” When exact match
Example of arrays :
Array1 = [2,7,6]
ReferenceArray= [2,9,7]
Hint= [“Almost”, “Not Quite”];
Code I have so far:
function check( array1, referenceArray ) {
let hint=[];
for(i=0;i<referenceArray.length;i++){
for (j=0;j<Array1.length;j++){
//value and position match
if ((referenceArray[i] && reference.indexOf[i]) === (Array1[j] && Array1.indexOf[j])) {
return hint.push('almost');
}
//value matches but not position
else if(( referenceArray[i] ===Array1[j]) && !(referenceArray.indexOf[i]===Array1.indexOf[j] )){
return hint.push('not quite');
}
}// end of Array1 iteration
} // end of reference interation
// if all values and position match
if(referenceArray===Array1){
return hint.push("correct");
}
//if no values match
else if (referenceArray!==Array1){
return hintArray.push("incorrect");
}
I would use some built in Array methods to help achieve this: every(), map() and findIndex().
I generally avoid using .push() because it mutates the array. Immutable code is nice to read 😉
const check = (array, referenceArray) => {
if (array.every((val, index) => val === referenceArray[index] )) {
return ['Correct']
}
const allHints = array.map((val, index) => {
const refArrayIndex = referenceArray.findIndex(refVal => val === refVal);
if (refArrayIndex === index) {
return 'Almost'
}
if (refArrayIndex !== -1) {
return 'Not Quite'
}
return undefined
});
const hints = allHints.filter((hint) => hint !== undefined);
if (hints.length > 0) {
return hints;
}
return ['Incorrect']
};
const hints = check([2,7,6],[2,9,7]);
console.log('hints', hints)
I did this code, tell me if it works or not 😁
const array1 = [2,7,6]
const ReferenceArray = [2,9,7]
function compareArrays(arr){
let perfect = true
for(let i = 0; i < ReferenceArray.length; i++){
if(ReferenceArray[i] != arr[i]) {
perfect = false
break
}
}
if(perfect) return 'correct'
let hint = []
for(let i = 0; i < ReferenceArray.length; i++){
if(arr[i] == ReferenceArray[i]) hint.push('Almost')
else if(ReferenceArray.includes(arr[i])) hint.push('Not Quite')
}
if(hint.length > 0) return hint
return 'incorrect'
}
console.log(compareArrays(array1))
I have an assignment where I am supposed to check two arrays (unsorted) with integers, to see if
They have the same length
The first element contains integers and the second has the same values squared, in any order
For example:
test([5,4,1], [1,16,25]) // would return true ..
What I've done so far is first sort the two input arrays, and then compare the length. Once we confirm the length is the same we iterate through each value to make sure they're equal. Keep in mind I haven't gotten to comparing the values to their squared counterpart yet, because my loop is not giving me expected results. Here is the code:
function test(arr1, arr2){
// sort arrays
const arr1Sort = arr1.sort(),
arr2Sort = arr2.sort();
// compare length and then compare values
if(arr1Sort.length === arr2Sort.length) {
for(let i = 0; i < arr1Sort.length; i++) {
if(arr1Sort[i] === arr2Sort[i]) {
return true;
} else {
return false;
}
}
}
}
console.log(test([1,2,3], [1,5,4])); returns true but the array values are different?!
Inside the for, no matter whether the if or else is fulfilled, the function will immediately return true or false on the first iteration - it'll never get past index 0. To start with, return true only after the loop has concluded, and return false if arr1Sort[i] ** 2 !== arr2Sort[i] (to check if the first squared equals the second).
Also, when sorting, make sure to use a callback function to compare each item's difference, because otherwise, .sort will sort lexiographically (eg, [1, 11, 2]):
function comp(arr1, arr2){
// sort arrays
const sortCb = (a, b) => a - b;
const arr1Sort = arr1.sort(sortCb),
arr2Sort = arr2.sort(sortCb);
// compare length and then compare values
if(arr1Sort.length !== arr2Sort.length) {
return false;
}
for(let i = 0; i < arr1Sort.length; i++) {
if(arr1Sort[i] ** 2 !== arr2Sort[i]) {
return false;
}
}
return true;
}
console.log(comp([1,2,3], [1,5,4]));
console.log(comp([5,4,1], [1,16,25]));
You can decrease the computational complexity to O(N) instead of O(N log N) by turning arr2 into an object indexed by the squared number beforehand:
function comp(arr1, arr2){
if (arr1.length !== arr2.length) {
return false;
}
const arr2Obj = arr2.reduce((a, num) => {
a[num] = (a[num] || 0) + 1;
return a;
}, {});
for (let i = 0; i < arr1.length; i++) {
const sq = arr1[i] ** 2;
if (!arr2Obj[sq]) {
return false;
}
arr2Obj[sq]--;
}
return true;
}
console.log(comp([1,2,3], [1,5,4]));
console.log(comp([5,4,1], [1,16,25]));
(if duplicates weren't permitted, this would be a lot easier with a Set instead, but they are, unfortunately)
This should work, no mater the data to compare:
function similar(needle, haystack, exact){
if(needle === haystack){
return true;
}
if(needle instanceof Date && haystack instanceof Date){
return needle.getTime() === haystack.getTime();
}
if(!needle || !haystack || (typeof needle !== 'object' && typeof haystack !== 'object')){
return needle === haystack;
}
if(needle === null || needle === undefined || haystack === null || haystack === undefined || needle.prototype !== haystack.prototype){
return false;
}
var keys = Object.keys(needle);
if(exact && keys.length !== Object.keys(haystack).length){
return false;
}
return keys.every(function(k){
return similar(needle[k], haystack[k]);
});
}
console.log(similar(['a', {cool:'stuff', yes:1}, 7], ['a', {cool:'stuff', yes:1}, 7], true));
// not exact
console.log(similar(['a', {cool:'stuff', yes:1}, 7], ['a', {cool:'stuff', stuff:'more', yes:1}, 7, 'more stuff only at the end for numeric array']));
Hi I am creating a function that returns the smallest number within the given array. If the array contains no numbers, it should return 0.
Here's my function:
function findSmallestNumberAmongMixedElements(arr){
if(arr.length === 0 && typeof arr === 'string'){
return 0;
} else{
return Math.min.apply(null, arr); //min=1
}
}
var output = findSmallestNumberAmongMixedElements([4, 'lincoln', 9, 'octopus']);
console.log(output); // --> 4
Right now my answer return NAN instead of 4. Do you have any idea what am I doing wrong?
typeof arr === "string" will always be false if you are passing an array (wether or not the array contain strings is irrelevant for that test).
What you should do is first, filter the numbers out of the array using filter, then call Math.min on the filtered array:
function findSmallestNumberAmongMixedElements(arr) {
var onlyNumbers = arr.filter(e => typeof e === "number"); // filter out only items that are numbers
if(onlyNumbers.length === 0) return 0; // if there is no numbers, return 0
return Math.min.apply(null, onlyNumbers); // otherwise return the min of them
}
var output = findSmallestNumberAmongMixedElements([4, 'lincoln', 9, 'octopus']);
console.log(output); // --> 4
Your current function may produce NaN when you try to apply Math.min to an input array which contains both string and number values. Math.min can only handle numeric inputs, so the presence of a string may cause it to return the NaN error value.
There is a simple solution: filter out all of the non-number values from the array. We can check the length of the filtered array to see if there were any non-numeric values and, if so, apply Math.min without worry.
function findSmallestNumberAmongMixedElements(arr) {
var filtered = arr.filter(function(el) {
return typeof el == 'number';
});
if (filtered.length > 0) {
return Math.min.apply(Math, filtered);
} else {
return 0;
}
}
[
[4, 'lincoln', 9, 'octopus'], // 4
[], // 0
['a', 3, 2], // 2
['h', 'i'], // 0
['-3', 3], // 3
].forEach(function(input) {
console.log(input, findSmallestNumberAmongMixedElements(input));
});
In your Math.min.apply(null, arr), you are getting NaN because there are strings in the array.
Your typeof arr === 'string' does not loop through your array to exclude string value within the array.
What you need to do to achieve your goal is to probably just do a for loop or forEach loop:
function findSmallestNumberAmongMixedElements(arr){
var min = Infinity;
// if argument is not array or array has no value
if (arr.constructor !== Array || arr.length === 0){
min = 0;
return min;
}
/* for loop */
for (var i = 0, len = arr.length; i < len; i++){
if (arr[i] === 0 || typeof arr[i] !== 'number') continue;
min = Math.min(min, arr[i]);
}
/* forEach loop */
arr.forEach(function(value, index){
if (value === 0 || typeof value !== 'number') return;
min = Math.min(min, value);
});
return min;
}
var output = findSmallestNumberAmongMixedElements([4, 'lincoln', 9, 'octopus']);
console.log(output); // --> 4
I think you should filter your array before giving it to Math.min
Try the following
function isNumber (obj) {
return obj!== undefined && typeof(obj) === 'number' && !isNaN(obj);
}
function smallestInMixedArray (arr) {
if (arr.length === 0 || !arr.filter) {
return 0;
} else {
arr = arr.filter(isNumber)
return Math.min.apply(null, arr); //min=1
}
}
var output = smallestInMixedArray([4, 'lincoln', 9, 'octopus']);
console.log(output); // --> 4
Given an array of mixed types, "getLongestWordOfMixedElements" returns the longest string in the given array.
Notes:
If the array is empty, it should return an empty string ("").
If the array contains no strings; it should return an empty string.
How do I find out if the array contains a string or not, as in this code:
function getLongestWordOfMixedElements(arr) {
if (arr.length === 0) return ""
var max = 0
for (var i = 0; i < arr.length; i++){
if(arr[i].length > max) max = arr[i]
}
return max
}
getLongestWordOfMixedElements([3, 'word', 5, 'up', 3, 1]);
You can filter the array for strings then use a reduce operation to find the longest one
function getLongestWordOfMixedElements(arr) {
return arr
.filter(item => typeof item === 'string')
.reduce((longest, str) => str.length > longest.length ? str : longest, '');
}
console.log(getLongestWordOfMixedElements([3, 'word', 5, 'up', 3, 1]));
Note that if any words are the same length, the earlier one in the array is returned.
Additionally, you could skip the filter and do the type check in the reduce...
return arr.reduce((longest, str) => {
return typeof str === 'string' && str.length > longest.length ?
str : longest;
}, '')
Well here's my version of it...
function getLongestWordOfMixedElements(arr) {
let result = '';
if (arr.length) {
for(i in arr) {
const value = arr[i];
if (value && typeof value === 'string' && value.length > result.length) {
result = value;
}
}
}
return result;
}
getLongestWordOfMixedElements([333333, 'word', 5, 'up', 3, 1]);
You iterate over the element and check if its type is a string.
You can do so with typeof.
Let us say you would've a bunch of data and would not like to double your memory usage / or for the sake of the example in your code:
function getLongestWordOfMixedElements(arr) {
var max = "";
if (arr.length) {
arr.forEach(function (item) {
if (typeof item === "string" && item.length > max) {
max = item;
}
});
}
return max;
}
console.log(getLongestWordOfMixedElements([3, 'word', 5, 'up', 3, 1, {foo:4}]));
In your code you would change it this way:
for (var i = 0; i < arr.length; i++) {
var item = arr[i];
if (typeof item === "string" && item.length > max) {
max = arr[i];
}
}
For example, Hello World! and Hi World! - the first occurrence of the difference is at the second character. What would be the JavaScript/jQuery function?
Assuming, like other answers, that matching strings return -1:
// Find common prefix of strings a and b.
var prefix = function(a,b){
return a && a[0] === b[0] ? a[0] + prefix(a.slice(1), b.slice(1)) : '';
};
// Find index of first difference.
var diff = function(a,b){
return a===b ? -1 : prefix(a,b).length;
};
var tests = [
['Hello World!', 'Hi World!'],
['aaabab', 'aaabzbzz'],
['', ''],
['abc', 'abc'],
['qrs', 'tu'],
['abc', ''],
['', 'abc']
];
console.log('diff', tests.map(test => diff(test[0], test[1])));
// Or just count up to the first difference
// Trickier nested ternary to handle the -1 however.
var diff2 = function(a,b){
return a === b ? -1 : a[0] === b[0] ? 1 + diff2(a.slice(1), b.slice(1)) : 0;
};
console.log('diff2', tests.map(test => diff2(test[0], test[1])));
Maybe something like this? It returns, in that order, the position of the first
difference if there's any, the length of the shortest string if those are different, or -1 if everything is equal.
function findDiff(a, b) {
a = a.toString();
b = b.toString();
for (var i = 0; i < Math.min(a.length, b.length); i++) {
if (a.charAt(i) !== b.charAt(i)) { return i; }
}
if (a.length !== b.length) { return Math.min(a.length, b.length); }
return -1;
}
Thanks Phil for the suggestions!
function strDiff(first, second) {
if(first==second)
return -1;
first = first.toString();
second = second.toString();
var minLen = min(first.length,second.length);
for(var i = 0; i<minLen; i++) {
if(first.charAt(i) != second.charAt(i)) {
return i;
}
}
return minLen;
}
Returns -1 if the strings do not differ, or the index (starting at 0) of the character at which they do (this is the length of the shortest string if they only differ by being different lengths, e.g. 'abcd' and 'abcdef' would return 4.
function firstDiff(a, b) {
var i = 0;
while (a.charAt(i) === b.charAt(i))
if (a.charAt(i++) === '')
return -1;
return i;
}
Returns the position where the two strings a and b first differ or -1 if they are equal.
A more efficient but less readable version:
function firstDiff(a, b) {
for (var i = 0, c; (c = a.charAt(i)) === b.charAt(i); ++i)
if (c === '')
return -1;
return i;
}
If you feel that you should first stringify the arguments, then do it in the invocation:
firstDiff(toString(a), toString(b))
Most often that will be a waste of time. Know your data!