sodiray / radash

Functional utility library - modern, simple, typed, powerful
https://radash-docs.vercel.app
MIT License
4.1k stars 160 forks source link

Add product function #377

Open dolsem opened 6 months ago

dolsem commented 6 months ago

Description

This PR adds a product function that takes N arrays as arguments and outputs the Cartesian product, for example:

produce(['a', 'b'], [1, 2]) // => [['a', 1], ['a', 2], ['b', 1], ['b', 2]]

Checklist

Resolves

If the PR resolves an open issue tag it here. For example, Resolves #34

vercel[bot] commented 6 months ago

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
radash-docs ✅ Ready (Inspect) Visit Preview 💬 Add feedback Feb 16, 2024 3:44am
aleclarson commented 1 week ago

Hey @dolsem, we might be interested in merging this over at the Radashi fork. You're invited to re-submit this PR there, but please specify how you use this function. 😄

P.S. You can read my post to learn more about the differences between Radashi and its predecessor.

BarleyBig commented 3 days ago

Hey @dolsem I found your Cartesian product function code, Is very beautifully and has extremely high performance. I think we can do some more optimization.

Cartesian product generally generates a relatively long result array, and the array size may be adjusted many times during the process. We can completely pre-calculate the length of the result array and initialize it, like this: const result = new Array(arrays.reduce((pre, curr) => pre * curr.length, 1));

indices init can be simpler and faster. Using const indices = arrays.map(() => 0) will be faster than new Array(arrays.length).fill(0) 。 The complete example is as follows:

export function product(arrays) {
    if (!arrays || !arrays.length || arrays.some(p => p.length < 1)) {
        return [];
    }
    const indices = arrays.map(() => 0)
    let currentIndex = arrays.length - 1;
    let resultIndex = 0
    const result = new Array(arrays.reduce((pre, curr) => pre * curr.length, 1));
    while (indices[0] < arrays[0].length) {
        result[resultIndex] = indices.map((j, i) => arrays[i][j])
        indices[currentIndex] += 1;
        while (currentIndex > 0 && indices[currentIndex] === arrays[currentIndex].length) {
            indices[currentIndex] = 0;
            indices[currentIndex - 1] += 1;
            currentIndex -= 1;
        }
        currentIndex = arrays.length - 1;
        resultIndex++
    }
    return result;
}

I ran some benchmarks and found it to be nearly 10% faster。 Thank you for creating such a useful function. I look forward to hearing your thoughts.