Merge Version Spec Strings

Benchmark created on


Description

Compare algorithms implementing the following behavior: A version Spec string is comma separated string of version numbers or version number ranges. Like "1,10-20,24,98-100". A merge operation among version spec strings must result in a string that takes both specifications and merge them.

Setup

var versionString1  = '1-999745,999830-999864';
var versionString2 = '999746-999829,999865-999979';
var validInputRegex = /^\s*(\d+(-\d+)?)(,\s*\d+(-\d+)?)*\s*$/;

Test runner

Ready to run.

Testing in
TestOps/sec
Exhaustive list of version numbers
function mergeVersionStrings(versions1, versions2) {
    const parsedVersions1 = parseVersions(versions1);
    const parsedVersions2 = parseVersions(versions2);
    return generateVersionsString(sortAndRemoveDuplicates([...parsedVersions1, ...parsedVersions2]));
}

function parseVersions(versions) {
    // Check if the input string matches any of the expected formats
    if (!versions || versions.trim().length == 0 || versions === 'undefined') {
        return [];
    }

    if (!versions.match(validInputRegex)) {
        throw new Error(`Invalid input format. Expected format: '3' or '1,2,3' or '1-3'. Received: ${versions}`);

    }

    const result = [];
    const sections = versions.split(',');

    for (const section of sections) {
        if (section.includes('-')) {
            const [start, end] = section.split('-').map(Number);
            for (let i = start; i <= end; i++) {
                result.push(i);
            }
        } else {
            result.push(Number(section));
        }
    }

    return result;

}

function sortAndRemoveDuplicates(versions) {
    return Array.from(new Set(versions)).sort((a, b) => a - b);
}

function generateVersionsString(versions) {
    if (versions.length === 0) {
        return '';
    }
    let result = '';
    let normalizedVersions = sortAndRemoveDuplicates(versions);
    let rangeStart = normalizedVersions[0];
    let rangeEnd = normalizedVersions[0];

    for (let i = 1; i < normalizedVersions.length; i++) {
        if (normalizedVersions[i] === rangeEnd + 1) {
            rangeEnd = normalizedVersions[i];
        } else {
            result += (rangeStart === rangeEnd ? rangeStart : `${rangeStart}-${rangeEnd}`) + ',';
            rangeStart = normalizedVersions[i];
            rangeEnd = normalizedVersions[i];
        }
    }

    result += (rangeStart === rangeEnd ? rangeStart : `${rangeStart}-${rangeEnd}`);
    return result;
}
mergeVersionStrings(versionString1, versionString2);
ready
Handle only specified ranges
function mergeVersionStrings(a, b) {
    const rangesA = parseVersionString(a);
    const rangesB = parseVersionString(b);
    const mergedRanges = optimizeRanges(rangesA.concat(rangesB));
    return formatVersionString(mergedRanges);
}

function parseVersionString(versionString) {
    const ranges = [];
    if (!versionString || !versionString.trim()) {
        return ranges;
    }
    const parts = versionString.split(',');
    for (const part of parts) {
        if (part.includes('-')) {
            const [start, end] = part.split('-').map(Number);
            ranges.push({start, end});
        } else {
            const num = Number(part);
            ranges.push({start: num, end: num});
        }
    }
    return optimizeRanges(ranges);
}

function optimizeRanges(ranges) {
    return ranges
        .sort((a, b) => a.start - b.start)
        .reduce((optimized, current) => {
            const last = optimized[optimized.length - 1];
            if (!last || current.start > last.end + 1) {
                optimized.push(current);
            } else {
                last.end = Math.max(last.end, current.end);
            }
            return optimized;
        }, []);
}

function formatVersionString(ranges) {
    return ranges
        .map((range) => (range.start === range.end ? `${range.start}` : `${range.start}-${range.end}`))
        .join(',');
}
mergeVersionStrings(versionString1, versionString2);
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.