开发者

Sorting function?

I need to organize an array of strings of random length into the least number of new strings with a max size. Is there a function or something in javascript, or something that can be translated to javascript, that will do this?

For example, the new strings might have max lengths of 1000 characters. The array might have strings of lengths 100, 48, 29, etc开发者_JS百科. I would want to combine those strings into as few new strings as possible.

edit: Sorry if this doesn't make sense, I tried my best.


No standard method in Javascript, but plenty of theoretical work has been done on this (i.e. the bin packing problem).

http://en.wikipedia.org/wiki/Bin_packing_problem

Some sample pseudo code in the link - should be trivial to translate to javascript.

The algorithm shown isn't going to be optimal in every case. To find the optimal solution to your example you'll just need to iterate over every possibility which might not be that bad depending on how many strings you have.


For my own entertainment, I wrote a simple bin packing algorithm. I picked a simple algorithm which is to sort the input strings by length. Create a new bin. Put the first (longest remaining) string into the bin and then keep filling it up with the longest strings that will fit until no more strings will fit. Create a new bin, repeat. To test it, I allocate an array of strings of random lengths and use that as input. You can see the output visually here: http://jsfiddle.net/jfriend00/FqPKe/.

Running it a bunch of times, it gets a fill percentage of between 91-98%, usually around 96%. Obviously the fill percentage is higher if there are more short strings to fill with.

Here's the code:

function generateRandomLengthStringArrays(num, maxLen) {
    var sourceChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXY1234567890";
    var sourceIndex = 0;
    var result = [];
    var len, temp, fill;

    function getNextSourceChar() {
        var ch = sourceChars.charAt(sourceIndex++);
        if (sourceIndex >= sourceChars.length) {
            sourceIndex = 0;
        }
        return(ch);
    }

    for (var i = 0; i < num; i++) {
        len = Math.floor(Math.random() * maxLen);
        temp = new String();
        fill = getNextSourceChar();
        // create string
        for (var j = 0; j < len; j++) {
            temp += fill;
        }
        result.push(temp);
    }
    return(result);
}

function packIntoFewestBins(input, maxLen) {
    // we assume that none of the strings in input are longer than maxLen (they wouldn't fit in any bin)

    var result = [];
    // algorithm here is to put the longest string into a bin and 
    // then find the next longest one that will fit into that bin with it
    // repeat until nothing more fits in the bin, put next longest into a new bin
    // rinse, lather, repeat

    var bin, i, tryAgain, binLen;
    // sort the input strings by length (longest first)
    input.sort(function(a, b) {return(b.length - a.length)});
    while (input.length > 0) {
        bin = new String();                      // create new bin 
        bin += input.shift();                    // put first one in (longest we have left) and remove it
        tryAgain = true;
        while (bin.length < maxLen && tryAgain) {
            tryAgain = false;                    // if we don't find any more that fit, we'll stop after this iteration
            binLen = bin.length;                 // save locally for speed/convenience
            // find longest string left that will fit in the bin
            for (i = 0; i < input.length; i++) {
                if (input[i].length + binLen <= maxLen) {
                    bin += input[i];
                    input.splice(i, 1);            // remove this item from the array
                    tryAgain = true;               // try one more time
                    break;                         // break out of for loop
                }
            }
        }
        result.push(bin);
    }
    return(result);
}

var binLength = 60;
var numStrings = 100;
var list = generateRandomLengthStringArrays(numStrings, binLength);
var result = packIntoFewestBins(list, binLength);
var capacity = result.length * binLength;
var fillage = 0;
for (var i = 0; i < result.length; i++) {
    fillage += result[i].length;
    $("#result").append(result[i] + "<br>")
}


$("#summary").html(
    "Fill percentage: " + ((fillage/capacity) * 100).toFixed(1) + "%<br>" +
    "Number of Input Strings: " + numStrings + "<br>" +
    "Number of Output Bins: " + result.length + "<br>" +
    "Bin Legnth: " + binLength + "<br>"

);
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜