HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Multiply all elements in an array except one

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
elementsallarraymultiplyoneexcept

Problem

The problem is: loop through a list of numbers and for each one of them get the product of all the others and return a new array.

For example in [1,2,3,4,5] the third element should be 40 because 1 × 2 × 4 × 5 = 40

I'm looking for feedback on efficiency and good practices.



function main(numbers) {
var result = [];
for (var i in numbers) {
var n = 1;
for (var j in numbers) {
if (i != j) {
n *= numbers[j];
}
}
result.push(n);
}
return result;
}

var a = [2, 6, 9, 31, 55];

console.log(main(a).toString());

Solution

What you have shown is an \$O(n^2)\$ solution in that you use nested loops to determine the results.

I would suggest an \$O(2n)\$ approach:

function main(numbers) {
    // one iteration to get product of whole array
    var arrayProduct = numbers.reduce(function(product, value) {
        return product * value;
    }, 1);

    // one iteration to map new array values by dividing 
    // full array product by current value
    return numbers.map(function(value) {
        return arrayProduct / value;
    });
}


You could probably use for loops instead of Array functions to micro-optimize this, but if I put myself into the position of someone who might grade such an algorithmic challenge as this. I would probably be happier to see code like this, as it still meets the requirement to optimize the performance to \$O(2n)\$, while providing code that is more readable. In other words, I would rather see the reduce() and map() calls in a production code base unless I had a use case where I really needed to squeeze every drop of performance out of this function.

ES6 version:

const main = (numbers) => {
    const arrayProduct = numbers.reduce( (product, value) => product * value, 1);
    return numbers.map( (value) => arrayProduct / value );
}


One could also easily foresee a case where larger arrays could easily hit up against the Number.MAX_SAFE_INTEGER value in javascript (\$2exp53\$), so one might consider throwing an error at some point to abort the operation.

const main = (numbers) => {
    const arrayProduct = numbers.reduce(
        (product, value) => {
            const product = product * value;
            if (product >= Number.MAX_SAFE_INTEGER) {
                throw new RangeError('Product has reached Number.MAX_SAFE_INTEGER');
            }
            return product;
        },
        1
    );
    return numbers.map( (value) => arrayProduct / value );
}

Code Snippets

function main(numbers) {
    // one iteration to get product of whole array
    var arrayProduct = numbers.reduce(function(product, value) {
        return product * value;
    }, 1);

    // one iteration to map new array values by dividing 
    // full array product by current value
    return numbers.map(function(value) {
        return arrayProduct / value;
    });
}
const main = (numbers) => {
    const arrayProduct = numbers.reduce( (product, value) => product * value, 1);
    return numbers.map( (value) => arrayProduct / value );
}
const main = (numbers) => {
    const arrayProduct = numbers.reduce(
        (product, value) => {
            const product = product * value;
            if (product >= Number.MAX_SAFE_INTEGER) {
                throw new RangeError('Product has reached Number.MAX_SAFE_INTEGER');
            }
            return product;
        },
        1
    );
    return numbers.map( (value) => arrayProduct / value );
}

Context

StackExchange Code Review Q#160701, answer score: 8

Revisions (0)

No revisions yet.