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
Related
Have to create a function that return the sum of the element in the array but if the array is
["a","b","c"] // output : abc
So far I have
function calculateSumRecursion(array) {
//your code
if (array.length === 0 ) {
return 0
}
return array[0] + calculateSumRecursion(array.slice(1))
}
I found out how to calculate the sum of all numbers using recursion but when it's an array of string like
array = ["a","b","c"]
it returns me
// abc0
because of the if statement.. is there any way to say
if (array.length === 0) return nothing instead of a 0 (that work only when it's an array of number?)
You just need to return the only value in the array when the length is 1, rather than waiting until you get a length of 0. That way you are always summing compatible types (numbers or strings). Note that you still need a test for a 0 array length in case the function gets called with an empty array. In this case you need to choose what to return; as requested, it is 0.
function calculateSumRecursion(array) {
if (array.length === 0) {
return 0;
}
if (array.length === 1) {
return array[0];
}
return array[0] + calculateSumRecursion(array.slice(1))
}
console.log(calculateSumRecursion([1, 2, 3, 4, 5]));
console.log(calculateSumRecursion(['a', 'b', 'c']));
console.log(calculateSumRecursion([]));
let arr = [1,2,3,4,5] // output : abc
let sum = calculateSumRecursion(arr);
function calculateSumRecursion (arr) {
return arr.length ? arr.pop() + calculateSumRecursion(arr) : 0;
}
Slice version
let arr = [1,2,3,4,5] // output : abc
let sum = calculateSumRecursion(arr);
function calculateSumRecursion (arr) {
return arr.length ? arr[0] + calculateSumRecursion(arr.slice(1)) : 0;
}
Change return 0 to return "" which will add an empty string to the sum.
You have returned 0 when the array is empty.
Now, you are doing string operations so it is needed to return empty value (not zero) so it will be affordable to return "".
function calculateSumRecursion(array) {
return array.length === 0 ? "" : array[0] + calculateSumRecursion(array.slice(1));
}
There's a way easier way to do this:
function calculateSumRecursion(array) {
var out = array[0];
for (let i = 1; i < array.length; i++) {
out = out + array[i];
}
return out;
}
Return empty string on recursion base case. Just replace your return 0 to return ''.
const array = ['a', 'b', 'c'];
function calculateSumRecursion(array) {
if (array.length === 0) {
return '';
}
return array[0] + calculateSumRecursion(array.slice(1));
}
console.log(calculateSumRecursion(array));
If you are want to work with number also then check array length for zero as well as one.
const array = ['a', 'b', 'c', 'e'];
const array2 = [];
const array3 = [1, 2, 3];
function calculateSumRecursion(array) {
const rec =
array.length === 1
? array[0]
: array.length >= 1 && array[0] + calculateSumRecursion(array.slice(1));
return array.length === 0 ? 0 : rec;
}
console.log(calculateSumRecursion(array));
console.log(calculateSumRecursion(array2));
console.log(calculateSumRecursion(array3));
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']));
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.
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];
}
}
I tried finding the sum of all numbers of a nested array, but I don't get it to work correctly. This is what I tried:
function arraySum(i) {
sum = 0;
for (a = 0; a < i.length; a++) {
if (typeof i[a] == 'number') {
sum += i[a];
} else if (i[a] instanceof Array) {
sum += arraySum(i[a]);
}
}
return sum;
}
When you try it out with the array [[1,2,3],4,5], it gets 6 as the answer, instead of 15.
Does somebody know where there is a mistake in it?
The problem with your code is that the sum and a variables are global, instead of local. Because of this you get an infinite loop (a from the first entry in the function is reset by the second entry, so the same elements are processed again).
Fix it by adding var to where sum and a are declared to make them local to the function:
function arraySum(i) {
var sum=0; // missing var added
for(var a=0;a<i.length;a++){ // missing var added
if(typeof i[a]=="number"){
sum+=i[a];
}else if(i[a] instanceof Array){
sum+=arraySum(i[a]);
}
}
return sum;
}
Demo: http://jsbin.com/eGaFOLA/2/edit
I know it's late, but they say "is never late" :)
const sumNestedArray = arr => arr.flat(Infinity).reduce((a,b)=> a+b, 0)
const sumNestedArray = arr => arr.flat(Infinity).reduce((a,b)=> a+b, 0)
console.log(sumNestedArray([1,[2], [2, 3, [4]]]))
sumNestedArray([1,[2], [2, 3, [4]]])
For 2018 this solution is clean and functional:
let arr = [[ 1, 2, 3], 4, 5]
arr.flat().reduce((d, i) => d + i)
Documentation for flat and reduce.
Recurse, for example
function arraySum(x) {
var sum = 0, i;
if (typeof x === 'number')
return x;
else if (x instanceof Array)
for (i = 0; i < x.length; ++i)
sum += arraySum(x[i]);
return sum;
}
arraySum([[1,2,3],4,5]); // 15
I didn't optimise this so that it's clear, you may want some more logic before recursion.
The reason yours isn't working is because you need to var both sum and a.
You're missing two var in there. You've implicitly declared sum and a at window scope:
function arraySum(i) {
**var** sum=0;
for(**var** a=0;a<i.length;a++){
if(typeof i[a]=="number"){
sum+=i[a];
}else if(i[a] instanceof Array){
sum+=arraySum(i[a]);
}
}
return sum;
}
First of all why you use 'i' as input to function? we using 'i' to denote running index..
Regarding your question,you want 'a' to be local in your loop so instead of "for(a=0;..." instead write "for(var a=0;"
<html>
<body>
<script>
function NestedArraySummation(arr)
{
var sum=0;
for(var i=0;i<arr.length;i++)
{
if(typeof arr[i]=="number")
sum=sum+arr[i];
else if(arr[i] instanceof Array)
sum=sum+NestedArraySummation(arr[i]);
}
return sum;
}
var MyArray=[1,[2,3],4,10,[1,2]];
var Sum=NestedArraySummation(MyArray);
document.write(Sum);
</script>
</body>
</html>
This can be done with lodash _.flattenDeep and _.sum:
const arr = [[1, 2, 3], 4, 5];
arraySum(arr);
function arraySum(arr) {
var arrFlattens = _.flattenDeep(arr);
// => [1, 2, 3, 4, 5]
console.log(_.sum(arrFlattens));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Here you go:
(My assumption is that you want to parse strings, e.g., '13', into numbers in order include them in the sum. If not, just change isNumber to typeof val === 'number'.
function arraySum(arr) {
let sum = 0;
while (arr.length) {
const val = arr.pop();
const isArray = typeof val === 'object' && val.length !== undefined;
const isNumber = !isArray && !isNaN(sum + parseFloat(val));
if (isArray && val.length) {
sum += arraySum(val);
}
else if (isNumber) {
sum += parseFloat(val);
}
}
return sum;
}
console.log(arraySum([])); //0
console.log(arraySum([1, 1, 1, [3, 4, [8]], [4]])); //22
console.log(arraySum([1, 1, [], {}, 'l', 1, [3, 4, [8]], [4]])); //22
This was posted long ago but it might help others. I did the following and it seems to be working just fine
function countArray (array) {
//iterate through the array
for(let i = 0;i < array.length; i++){
//check if element of array is an array, and if it is, run method flat() to the whole array.
if(Array.isArray(array[i])){
array = array.flat()
}
}
//return the sum of the elements of the array
return array.reduce((a,b) => a + b);
}
from __builtin__ import int
def nestedLists(mylist):
sum = 0
if checkIfAllInt(mylist):
result = addList(mylist)
return result
else:
for value in mylist:
sum = sum + nestedLists(value)
return sum
def addList(listdata):
if(type(listdata) is int):
return listdata
else:
return sum(listdata)
def checkIfAllInt(listdata):
check = True
if(type(listdata) is int):
return check
else:
for value in listdata:
if(not type(value) is int):
check = False
return check
return check
print nestedLists([1,[2,3,[4,5,[6,7]]]])