按字母顺序列出,将少量条目的字母分组在一起(PHP或JS)

5
我正在开发一个Web应用程序,其中包含大量的名称列表。客户最初希望按字母将名称拆分为
,以便轻松地跳转到列表上的特定名称。
现在,查看列表时,客户指出有几个字母只与一个或两个名称相关联。如果每个名称中只有少数名称,他现在想知道我们是否可以合并连续的几个字母。
(请注意,没有名称的字母根本不显示。)
我现在所做的是让数据库服务器返回一个已排序的列表,然后保留一个包含当前字符的变量。我遍历名称列表,递增字符,并在到达每个字母时打印开放和关闭的
    标记。我知道如何调整此代码以组合一些字母,但我不确定如何处理特定字母组合是否为最佳可能的组合。换句话说,假设我有:
    A-12个名称 B-2个名称 C - 1个名称 D - 1个名称 E-1个名称 F-23个名称
    我知道如何得到一个A-C组合,然后单独有D。我正在寻找的是实现A应该单独存在,然后B-D应该在一起的高效方法。
    我真的不确定从哪里开始寻找。
    如果有任何区别的话,这段代码将用于Kohana Framework模块。
    更新2012-04-04:
    这是我需要的澄清:
    假设我希望每个组中的最小项目数为30。现在假设字母A有25项,字母B、C和D每个有10项,字母E有32项。我想保留A,因为合并B+C+D将更好。将它们简单地组合起来是A+B、C+D+E-这不是我想要的。
    换句话说,我需要最接近每组最小值的最佳匹配。

1
这里有一个 jsfiddle,提供了一份起始的名字列表,如果大家想要测试一下 js 方法的话可以使用。http://jsfiddle.net/Avveb/ - mrtsherman
我知道这可以通过一些大规模的动态规划来完成,但我希望有人能找到一些简单到足以在Web应用程序中使用的东西。如果我需要使用动态规划,我将不得不偶尔运行它并缓存结果,因为它将过于密集而无法在页面加载时运行。 - Moshe Katz
4个回答

1
我使用PHP编写了这个函数。它将组合起来有超过$ammount个名称的字母分组。
function split_by_initials($names,$ammount,$tollerance = 0) {
    $total = count($names);
    foreach($names as $name) {
        $filtered[$name[0]][] = $name;
    }
    $count = 0;
    $key = '';
    $temp = array();
    foreach ($filtered as $initial => $split) {
        $count += count($split);
        $temp = array_merge($split,$temp);
        $key .= $initial.'-'; 
        if ($count >= $ammount || $count >= $ammount - $tollerance) {
            $result[$key] = $temp;
            $count = 0;
            $key = '';
            $temp = array();
        }
    }
    return $result;
}

第三个参数用于限制仅包含单个字母且数量不足,但足够接近的情况。
例如,我想将其分成每组30个,但其中A只有25个。因此,如果您设置了5的容差,则A将被单独留下,其他字母将被分组。
我忘记提到它会返回一个多维数组,以包含的字母为键,然后是其中包含的名称。
类似于
Array ( [A-B-C-] => Array ( [0] => Bandice Bergen [1] => Arey Lowell [2] => Carmen Miranda ) )
这不完全是您所需的,但我认为它足够接近。

1
如果一封信包含超过10个名称,或者您设置的任何合理限制,请不要将其与下一封信组合。但是,如果您开始组合信件,如果您愿意,可以让它运行到收集了15个左右的名称,只要没有单个信件超过10个名称。这不是一个通用的解决方案,但这就是我会解决它的方式。

这可能就是我最终要做的事情。不幸的是,这并不是我希望做的事情。 - Moshe Katz

0

Javascript版本:增强版,具有排序和符号分组功能

function group_by_initials(names,ammount,tollerance) {
        tolerance=tollerance||0;
        total = names.length;
        var filtered={}
        var result={};
        $.each(names,function(key,value){
            val=value.trim();
            var pattern = /[a-zA-Z0-9&_\.-]/
            if(val[0].match(pattern)) {
                intial=val[0];
            }
            else
            {
                intial='sym';
            }
            if(!(intial in filtered))
                filtered[intial]=[];

            filtered[intial].push(val);
        })
        var count = 0;
        var key = '';
        var temp = [];
        $.each(Object.keys(filtered).sort(),function(ky,value){
            count += filtered[value].length;
            temp = temp.concat(filtered[value])
            key += value+'-'; 
            if (count >= ammount || count >= ammount - tollerance) {
                key = key.substring(0, key.length - 1);
                result[key] = temp;
                count = 0;
                key = '';
                temp = [];
            }
        }) 
        return result;
    }

0

使用mrsherman提供的jsfiddle,我想出了一个可能可行的解决方案:http://jsfiddle.net/F2Ahh/

显然,这只是用作伪代码,可以应用一些技巧使其更有效率。但这已经完成了任务。


那不是我想要的。我已经有可以像那样分解它们的代码了,只需在此组小于最小值时添加下一组即可。请查看我对问题的更新。 - Moshe Katz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接