0

私は、朝食、昼食、夕食の 3 つのカテゴリからのレシピの配列を持っています。これらの各カテゴリには、10 個のユニークなレシピがあります。

$recipes = [
    'breakfast' => [
        0 => [
            'title' => 'eggless waffles',
            'calorie' => 210,
        ],
        1 => [
            'title' => 'blueberry oatmeal',
            'calorie' => 161,
        ],
        ...
     ],
    'lunch' => [9],
    'dinner' => [9]
];

毎日3種類のレシピを並べ替えて組み合わせを作りたい

$days = array_fill(0, 6, [1 => [], 2 => [], 3 => []]);

各レシピにはカロリー量があり、各最終日には、500 に最も近い 3 つのレシピの組み合わせで注文されたレシピとの組み合わせ (朝食 1 回、昼食 1 回、夕食 1 回からなる) が必要です。

たとえば、1 日目の組み合わせのレシピ (朝食、昼食、夕食) のカロリーの合計が 660 で、2 日目が 400 だった場合、朝食を 2 日目から 1 日目に切り替えると、両方が 500 に最も近くなる可能性がありますが、それは可能です。 3 日目の朝食を 1 日目に、2 日目を 3 日目に切り替えると、3 つすべてのヒットが 500 に近づく可能性があります。

したがって、1 日目、2 日目、3 日目、4 日目、5 日目、6 日目、7 日目には 3 つのレシピ (朝食、昼食、夕食) が必要です。

$final = [
    0 => [
        'breakfast' => [...],
        'lunch' => [...],
        'dinner' => [...],
    ],
     1 => [
        'breakfast' => [...],
        'lunch' => [...],
        'dinner' => [...],
    ],
    2 => [
        'breakfast' => [...],
        'lunch' => [...],
        'dinner' => [...],
    ],
    ...
];

行き詰まりになってから数日が経ちましたが、これらの配列を毎日 3 つの組み合わせに並べ替える方法がわかりません。(私はオフにするための多くのコードを提供していないことを知っています)

編集1:これは私がこれまでに得たものです:

class Combinations {

    private $days;

    public function __construct(){
        $this->days = array_fill(1, 7, [1 => [], 2 => [], 3 => []]);
    }

    public function create(){
        $median = 600;

        foreach($this->days as $day => $categories){
            while($this->dayIsIncomplete($day)){
                $recipes = [];
                foreach($categories as $category => $value){
                    $recipes[$category] = $this->getRandomRecipe($category);
                }

                // add random meals to first day
                if($day === 1){
                    $this->days[$day] = $recipes;
                    continue;
                }

                foreach($recipes as $category => $recipe){
                    foreach($this->days as $dayKey => $mealsArray){
                        $originalMacros = $this->totalMacros($mealsArray);

                        // remove $recipe category from mealsArray, and merge it ($recipe)
                        $filteredMacros = $this->totalMacros(array_merge([$recipe], array_filter($mealsArray, function($key) use($category){
                            return $key !== $category;
                        }, ARRAY_FILTER_USE_KEY)));

                        // if original is not closer to median
                        if(($originalMacros - $median) * ($originalMacros - $median) < ($filteredMacros - $median) * ($filteredMacros - $median)){
                            // flip current recipes
                            // switch D2B ($recipe) with D1B
                        }
                    }
                }
            }
        }
    }

    public function getRandomRecipe(int $category){
        $recipes = []

        if($category === 1){
            $recipes[] = ['id' => 1, 'calorie' => 310];
            $recipes[] = ['id' => 2, 'calorie' => 360];
            $recipes[] = ['id' => 3, 'calorie' => 450];
            $recipes[] = ['id' => 4, 'calorie' => 330];
            $recipes[] = ['id' => 5, 'calorie' => 220];
            $recipes[] = ['id' => 6, 'calorie' => 390];
            $recipes[] = ['id' => 7, 'calorie' => 400];
            $recipes[] = ['id' => 8, 'calorie' => 320];
            $recipes[] = ['id' => 9, 'calorie' => 460];
        }

        if($category === 2){
            $recipes[] = ['id' => 10, 'calorie' => 420];
            $recipes[] = ['id' => 11, 'calorie' => 360];
            $recipes[] = ['id' => 12, 'calorie' => 450];
            $recipes[] = ['id' => 13, 'calorie' => 310];
            $recipes[] = ['id' => 14, 'calorie' => 320];
            $recipes[] = ['id' => 15, 'calorie' => 490];
            $recipes[] = ['id' => 16, 'calorie' => 440];
            $recipes[] = ['id' => 17, 'calorie' => 520];
            $recipes[] = ['id' => 18, 'calorie' => 560];
        }

        if($category === 3){
            $recipes[] = ['id' => 19, 'calorie' => 510];
            $recipes[] = ['id' => 20, 'calorie' => 660];
            $recipes[] = ['id' => 21, 'calorie' => 750];
            $recipes[] = ['id' => 22, 'calorie' => 610];
            $recipes[] = ['id' => 23, 'calorie' => 580];
            $recipes[] = ['id' => 24, 'calorie' => 690];
            $recipes[] = ['id' => 25, 'calorie' => 710];
            $recipes[] = ['id' => 26, 'calorie' => 620];
            $recipes[] = ['id' => 27, 'calorie' => 730];
        }

        return $recipes[array_rand($recipes)];
    }

    public function dayIsIncomplete($day){
       return !empty($this->days[$day][1]) && !empty($this->days[$day][2]) && !empty($this->days[$day][3]);
    }

    public function totalMacros($array){
        $total = 0;
        foreach ($array as $key => $value) {
            $total += $value['calorie'];
        }
        return $total / 2;
    }
}

編集2:

この問題を解決するのに最適なアルゴリズムを見つけようとしています。二部一致(最大)アルゴリズムを使用することが必要だと思います。

編集3:

時間を割いていただきありがとうございます。答えを忘れていません。とりあえずこれは脇に置いておかなければなりませんでしたが、すぐに取り掛かることができ、受け入れられた回答が残りの 300 の報奨金を獲得します。

4

3 に答える 3