在做商城系統中最常見的就是規格,簡寫pcs。具體來說就是一個商品有多個屬性,每個屬性有多個規格,這樣就形成一些排列組合,做商品庫存的時候就要對這些組合進行設定庫存和價格。
比如,一臺電腦記憶體有16G,32G和64G的,硬碟有500G和1T的,顯示卡有整合顯示卡和獨立顯示卡的,這樣的商品在售賣的時候選定不同規格價格不一樣,倉庫備貨的庫存當然也不一樣。
那麼對商城後臺而言就要單獨設定這些產品的價格,就需要把所有的組合排列出來設定價格。
現在我們已知應該產生這樣的排列組合然後設定價格和庫存(這裡面的價格和庫存只是為了程式舉個例子 並不是實際市場上賣這個價格)
記憶體 | 硬碟 | 顯示卡 | 價格 | 庫存 |
16G | 500G | 整合 | 5000 | 100 |
16G | 500G | 獨立 | 6000 | 200 |
16G | 1T | 整合 | 7000 | 220 |
16G | 1T | 獨立 | 6500 | 120 |
32G | 500G | 整合 | 7000 | 110 |
32G | 500G | 獨立 | 7500 | 200 |
32G | 1T | 整合 | 7500 | 300 |
32G | 1T | 獨立 | 8000 | 200 |
64G | 500G | 整合 | 7500 | 134 |
64G | 500G | 獨立 | 8000 | 347 |
64G | 1T | 整合 | 8500 | 258 |
64G | 1T | 獨立 | 9000 | 35 |
這裡一共是12種組合,那如何用程式生成這樣的組合呢?
我們已知從資料庫讀取能夠拿到的屬性變數如下:
<?php $spec_list = [ 'memory' => ['16G', '32G', '64G'], 'storage' => ['500G', '1T'], 'graphics' => ['integrated', 'discrete'], ];
我們想要的肯定是一個陣列,裡面有12個元素,每個元素中就是這些規格的組合。
類似於這樣的結果
[ ['16G', '500G', '整合'], ['16G', '500G', '獨立'], ['16G', '1T', '整合'], ['16G', '1T', '獨立'], ['32G', '500G', '整合'], ['32G', '500G', '獨立'], ['32G', '1T', '整合'], ['32G', '1T', '獨立'], ['64G', '500G', '整合'], ['64G', '500G', '獨立'], ['64G', '1T', '整合'], ['64G', '1T', '獨立'], ]
那麼怎麼實現呢?你要是寫三層迴圈,進行巢狀實現,那也沒問題,就是這個屬性的個數你得明確的知道有多少種,這樣畢竟不是長久之計,而且屬性有可能增加或者減少,那將來後臺增加了屬性,程式該怎麼辦呢?
還是得自動的計算出來所有組合,不需要手動去檢測有多少種屬性去foreach遍歷。
這裡我偷懶的讓vscode裡面的外掛 fitten code 幫我寫了一個
<?php function generateCombinations($attributes) { if (count($attributes) === 0) { return [[]]; } $firstAttribute = array_shift($attributes); $combinationsWithoutFirst = generateCombinations($attributes); $combinations = []; foreach ($firstAttribute as $value) { foreach ($combinationsWithoutFirst as $combination) { $combinations[] = array_merge([$value], $combination); } } return $combinations; }
呼叫一下看看
<?php $spec_list = [ 'memory' => ['16G', '32G', '64G'], 'storage' => ['500G', '1T'], 'graphics' => ['整合', '獨立'], ]; $combinations = generateCombinations($spec_list); var_dump($combinations);
從執行結果來看,是沒問題的。
果然是AI改變未來啊,這生成速度比我手動敲的快多了。但是我們也能發現,它用了遞迴,按道理來說,這種普通的規格屬性也不會太多,排列組合幾十個已經很多了,再多的話,客戶端那邊顯示就不好看了,而且客戶操作起來就不方便,那遞迴的效能也不會太差。
但是咱們是追求極致的人啊,我再寫個迴圈實現的,避免程式效率太低,看看怎麼實現呢?
首先得弄個大迴圈,在裡面一直進行迴圈,然後還得判斷這種組合是否有過,層數如何解決呢?
我想可以先實現二層,再實現多層,逐步增加組合列表,話不多說,看程式碼
<?php function get_combine_list($spec_list) { if (count($spec_list) <= 1) { return $spec_list; } $result = []; $first_item = array_shift($spec_list); foreach ($first_item as $first_value) { $result[] = [$first_value]; } while ($spec_list) { $tmp_result = []; $second = array_shift($spec_list); foreach ($result as $result_item) { foreach ($second as $second_value) { $tmp_result[] = array_merge($result_item, [$second_value]); } } $result = $tmp_result; } return $result; }
好了,同樣的程式碼呼叫一下
<?php $spec_list = [ 'memory' => ['16G', '32G', '64G'], 'storage' => ['500G', '1T'], 'graphics' => ['整合', '獨立'], ]; $combinations = get_combine_list($spec_list);
發現結果是一樣的,大功告成!
上面遞迴的思路是遞迴發現自己是不是最後一個,不是的話就再遞迴,最終找到最後一個,形成組合,然後再與倒數第二個組合,再與倒數第三個組合。
這裡我的思路是,先拿出第一個自然形成結果,再拿出第二個進行組合,然後拿出第三個跟現有結果進行組合,直到拿出最後一個規格進行組合最終形成結果賦值。
方法沒有優劣,只有是不是適合以及你自己能不能接受,能不能維護。