それで、
問題
SQL から、文字列を含む配列 (フラット配列) を取得しています。
$rgData = ['foo', 'bar', 'baz', 'bee', 'feo'];
ここで、この配列のペアとトリプレットの可能な組み合わせ (および、一般的なケースでは、4 つの要素などの組み合わせ) を取得したいと考えています。より具体的に言うと、数学的な意味での組み合わせ(重複なし)、つまり、カウントが等しい組み合わせを意味します
-上記の配列の場合、ペアとトリプレットの両方で10になります。
私のアプローチ
可能な値を可能な配列選択項目にマッピングすることから始めました。私の現在の解決策は、要素が「1」として選択されている場合はポイントし、それ以外の場合は「0」をポイントすることです。上記のサンプルでは、次のようになります。
フー・バー・バズ・ビー・フェオ 0 0 1 1 1 -> [バズ、ビー、フェオ] 0 1 0 1 1 -> [バー、ビー、フェオ] 0 1 1 0 1 -> [バー、バズ、フェオ] 0 1 1 1 0 -> [バー、バズ、ビー] 1 0 0 1 1 -> [フー、ビー、フェオ] 1 0 1 0 1 -> [フー、バズ、フェオ] 1 0 1 1 0 -> [フー、バズ、ビー] 1 1 0 0 1 -> [フー、バズ、フェオ] 1 1 0 1 0 -> [フー、バー、ビー] 1 1 1 0 0 -> [フー、バー、バズ]
そして、私がする必要があるのは、どうにかして目的のビットセットを生成することだけです。PHPでの私のコードは次のとおりです。
function nextAssoc($sAssoc)
{
if(false !== ($iPos = strrpos($sAssoc, '01')))
{
$sAssoc[$iPos] = '1';
$sAssoc[$iPos+1] = '0';
return substr($sAssoc, 0, $iPos+2).
str_repeat('0', substr_count(substr($sAssoc, $iPos+2), '0')).
str_repeat('1', substr_count(substr($sAssoc, $iPos+2), '1'));
}
return false;
}
function getAssoc(array $rgData, $iCount=2)
{
if(count($rgData)<$iCount)
{
return null;
}
$sAssoc = str_repeat('0', count($rgData)-$iCount).str_repeat('1', $iCount);
$rgResult = [];
do
{
$rgResult[]=array_intersect_key($rgData, array_filter(str_split($sAssoc)));
}
while($sAssoc=nextAssoc($sAssoc));
return $rgResult;
}
-ビットを通常の文字列として保存することにしました。次の関連付けを生成するための私のアルゴリズムは次のとおりです。
- 「01」を探してみてください。見つからない場合は、11..100..0 のケースです (つまり、最大値であり、それ以上は見つかりませんでした)。見つかった場合は、2 番目のステップに進みます
- 文字列の "01" の一番右の位置に移動します。「10」に切り替えてから、見つかった「01」位置よりも右側にあるすべてのゼロを左に移動します。たとえば、
01110
「01」の一番右の位置は 0 なので、まずこの「01」を「10」に切り替えます。文字列は現在 sill です10110
。次に、右側の部分 (10
部分がないため、0+2 = 2 番目のシンボルから開始) に移動し、すべてのゼロを左に移動します。つまり、110
になります011
。その結果、の次の関連付けとして10
+011
=が得られます。10111
01110
ここで同様の問題が見つかりました-しかし、OPは重複した組み合わせを望んでいますが、重複していないものを望んでいます。
質問
私の質問は次の 2 点です。
- 私の解決策では、次のビットセットをより効率的に生成する別の方法があるでしょうか?
- これにはもっと簡単な解決策があるでしょうか?標準問題のようです。