我有一个以下数组(php):
[
[id=>1,weight=]
[id=>2,weight=]
[id=>3,weight=]
[id=>4,weight=]
]
我需要创建此数组的所有可能版本,将 0-100 权重称为每个item['weight']
,步长为N.
我不知道如何调用这类问题。它不是排列/组合。
让我们说N是10,我的目标是:
[
[
[id=>1,weight=10]
[id=>2,weight=10]
[id=>3,weight=10]
[id=>4,weight=70]
]
[
[id=>1,weight=10]
[id=>2,weight=10]
[id=>3,weight=20]
[id=>4,weight=60]
]
[
[id=>1,weight=10]
[id=>2,weight=10]
[id=>3,weight=30]
[id=>4,weight=50]
]
[
[id=>1,weight=10]
[id=>2,weight=10]
[id=>3,weight=40]
[id=>4,weight=40]
]
...all possible combination of weights for id=x.
[
[id=>1,weight=70]
[id=>2,weight=10]
[id=>3,weight=10]
[id=>4,weight=10]
]
]
同一级别的数组中的item['weights']
的总和始终为100(或0.1)。在父母数组中,我为所有可能的权重组合从10到100为id = x。
答案 0 :(得分:1)
这个问题有时被描述为将相同的球分配到不同的箱中。你没有准确地指出你的问题,所以我会在这里猜测,但逻辑是相同的。
我假设你将b = N /步球分配到4个箱子里。
连续想想球,然后使用3个球将球分成4个箱: 的 * | 强> || *****
如果N = 10并且您正在分配100个点,则上面的示例是相同的是30,20,0,50。如果不允许使用零,则可以减少分配的数量4 * b并假设每个bin以N / step开头(所以你要分配剩余点)。
执行此操作的方法是选择(球+箱子 - 1,箱子 - 1)。
答案 1 :(得分:0)
Theres可能是一种更好的方式,但继承了我的尝试:
$result=array(); // Empty array for your result
$array=range(1117,7777); // Make an array with every number between 1117 and 7777
foreach ($array as $k=>$v) { // Loop through numbers
if ((preg_match('/[890]/',$v) === 0) && (array_sum(str_split($v, 1)) === 10)) {
// If number does not contain 8,9 or 0 and sum of all 4 numbers is 10
// Apply function to multiply each number by 10 and add to result array
$result[] = array_map("magnitude", str_split($v, 1));
}
}
function magnitude($val) { // function to multiply by 10 for array map
return($val * 10);
}
print_r($result);
工作演示here
修改强>
很抱歉,我意识到我的代码解释并不完全清楚,而且我将它简化得过于简单,以便于理解。
在您的示例中,第一个数组将包含(10,10,10,70)
。为了简单起见,我将所有内容除以10进行计算,然后在得到结果后再乘以10,这样(10,10,10,70)
的数组变为(1,1,1,7)
。然后你的最终数组将是(70,10,10,10)
,它将成为(7,1,1,1)
。
我的方法是首先创建一个包含这四个数字的每个组合的数组,我分两步完成。
这一行$array=range(1117,7777);
创建一个像(1117, 1118, 1119 ... 7775, 7776, 7777)
这样的数组(我的数字范围应该是1117 - 7111而不是1117-7777)。
将str_split($v, 1)
应用于循环中的每个值会将数组中的每个4位数字拆分为包含4个单个数字的另一个数组,因此1117
将变为(1, 1, 1, 7)
等
由于您的每件商品的重量不能低于10或高于70,我们会使用(preg_match('/[890]/',$v) === 0)
跳过任何位于其中0,8或9的数组,然后array_sum(str_split($v, 1)) === 10)
加起来数组中的四个数字,只返回总数为10的数组(你想要的总数为100,但我之前除以10)。
array_map
将函数应用于数组中的每个元素。在我的例子中,函数将每个值乘以10,以撤消之前除以10的事实。
当你说可以改变步骤时,你能给我一些其他值的例子以及你想要的输出吗?
如果你想要一个完全不同的方法并且使用mysql不是问题,那么这也有效:
创建一个包含单行的新表。插入您需要检查的所有值
INSERT INTO `numbers` (`number`) VALUES
(10),
(20),
(30),
(40),
(50),
(60),
(70);
然后你的php看起来像这样
$result=array();
try {
$dbh = new PDO('mysql:host=aaaaa;dbname=bbb', 'ccc', 'dddd');
foreach($dbh->query('SELECT *
FROM numbers a
CROSS JOIN // A cross join returns the cartesian product of rows
numbers b // so every row with every combination of the other rows
CROSS JOIN
numbers c
CROSS JOIN
numbers d
ON
a.number = b.number OR a.number != b.number') as $row) {
if (($row[0] + $row[1] + $row[2] + $row[3]) === 100) {
$result[] = $row;
}
}
$dbh = null;
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "<br/>";
die();
}
print_r($result);