我正在编写一种算法来生成数据库中的项目组合。它们需要是唯一的排列(即145,156 == 156,145)。我遇到的问题是如何跟踪以前的组合,这样我最终不会得到145,156和156,145。
目前我将它们添加到索引为id1_id2的数组中...(排序使得id始终从最低到最高)并在生成组合时将值设置为1,以便我可以检查$ combos [ $ index]是否存在。如果它不存在,请创建它。 (还有其他标准可以排除每个排列,但它们无关紧要)生成这些组合后,它们将存储在MySQL的表中。
我遇到的问题是,对于我正在使用的测试项目(大约85)我无法生成超过3个项目(id1_id2_id3)的组合,而不会耗尽内存,因为组合的数量是MASSIVE和$ combos数组占用超过我在PHP内存中分配的64M。
有没有办法可以做到这一点a)没有跟踪以前的组合或b)跳过$ combos数组路由并且只向mysql添加一个唯一行并让mysql处理重复检查。
以下是一些伪代码供参考:
$items = array(/*85 items*/);
foreach ($items as $item1){
generate(array($item1));
foreach($items as $item2){
generate(array($item1, $item2));
}
}
}
function generate($items_arary){
$temp_array = array();
foreach ($items_array as $item){
$temp_array[] = $item['id'];
}
sort($temp_array);
$index = implode("_", $temp_array);
if (!$combos[$index]){
$combos[$index] = 1;
/* some code to generate query to store to db */
}
}
查询最终看起来像这样:(数据库在脚本开头被截断)
INSERT INTO `combos` (combo_id, more_info) VALUES ('id1_id2', 'Item Name');
在撰写这个问题的过程中,我想到了一个可能的解决方案:确保id3> id2> ID1。这是否是一个可行的解决方案,以消除$ combos的需求?
答案 0 :(得分:3)
我之前询问过数据结构的原因是因为你可以这样做:
$sql = "SELECT id FROM test_a";
$result = mysql_query($sql);
while ($row = mysql_fetch_array($result)) {
$item1 = $row['id'];
$sql2 = "SELECT id FROM test_a";
$result2 = mysql_query($sql2);
while ($row2 = mysql_fetch_array($result2)) {
$item2 = $row2['id'];
$combo1 = $item1 . "_" . $item2;
$combo2 = $item2 . "_" . $item1;
$sql3 = "SELECT * FROM combos WHERE combo_id = '$combo1' OR combo_id = '$combo2'";
$result3 = mysql_query($sql3);
if (mysql_num_rows($result3) == 0) {
$sql4 = "INSERT INTO combos (combo_id, more_info) VALUES ('$combo1','Item Name')";
$result4 = mysql_query($sql4);
}
}
}
当表test_a具有值1,2,3和4时,此脚本将插入: 1_1 1_2 1_3 1_4 2_2 2_3 2_4 3_3 3_4 4_4
这不应该有任何内存问题。虽然如果你有一个庞大的数据库,你可能会遇到php的时间限制问题
答案 1 :(得分:1)
这是与我的其他答案相同的概念,但采用的是所有SQL格式。
INSERT INTO combos (combo_id, more_info)
SELECT CONCAT_WS("_",t1.id,t2.id), "item_name"
FROM test_a t1, test_a t2
WHERE NOT EXISTS (SELECT * FROM combos WHERE combo_id = CONCAT_WS("_",t1.id,t2.id))
AND NOT EXISTS (SELECT * FROM combos WHERE combo_id = CONCAT_WS("_",t2.id,t1.id))
假设您可以从某个地方的db获取item_name,这可能是您最快且内存最少的解决方案。我目前正在对大约1000个ids进行测试。完成后我会更新。
答案 2 :(得分:0)
是。您可以存储和使用组合的词典索引来重建/迭代它们,如果需要迭代所有这些,则可以使用格雷码。
看看:“算法515:从字典索引生成矢量”; Buckles,B.P。和Lybanon,M。ACM Transactions on Mathematical Software,Vol。 1977年6月3日第2期。
答案 3 :(得分:0)
如果您不需要自动强制执行参照完整性(如果使用字符串连接则不是这样),对85个项目使用一个表,为每个项目分配一个索引(0-84),并使用第二个表用于表示给定项集的表,使用数字数据类型,其中数字中的每个位位置代表一个项。 (例如000001101表示项目0,2和3)
对于超过64的项目,您可能需要将它们拆分为多个字段,或者使用BLOB或字符串(gack!)。
如果您将此作为主键字段使用,则可以强制执行非重复项。
答案 4 :(得分:0)
在TSQL中,您可以使用递归CTE,但不记得我在哪里获得它,但非常甜蜜。注意MYSQL没有使用"使用"选项,所以它不会在MySQL中工作
WITH Numbers(N) AS (
SELECT N
FROM ( VALUES(1), (2), (3), (4), (5), (6)) Numbers(N)),
Recur(N,Combination) AS (
SELECT N, CAST(N AS VARCHAR(20))
FROM Numbers
UNION ALL
SELECT n.N,CAST(r.Combination + ',' + CAST(n.N AS VARCHAR(10)) AS VARCHAR(20))
FROM Recur r
INNER JOIN Numbers n ON n.N > r.N)
select Combination
from RECUR
ORDER BY LEN(Combination),Combination;
答案 5 :(得分:-1)
增加记忆力变化
你的php.ini中的 memory_limit = 512M
或
你的php脚本中的ini_set('memory_limit','512M')
或
你的.htaccess中的php_value memory_limit 512M