????????最近項目遇到了一個難題,就是模仿淘寶上的選擇規(guī)格呀打,首先我先來解釋下什么是sku,sku(Stock Keeping Unit 庫存量單位)即庫存進出計量的基本單元,可以是以件搁嗓,盒,托盤等為單位箱靴。sku這是對于大型連鎖超市DC(配送中心)物流管理的一個必要的方法腺逛。上面的話可能你們沒有聽懂是什么意思,具體請打開手淘,選擇服裝類的產(chǎn)品(由于服裝類的產(chǎn)品可選規(guī)格較多衡怀,比較容易進行比較)棍矛。
????????當(dāng)時項目開始并不是采用這個sku算法,而是采用遍歷查詢的方式,將所有結(jié)果進行拆分抛杨,拆分成幾個不同屬性的集合够委;例如顏色、內(nèi)存怖现、大小等茁帽;然后通過用戶點擊按鈕,去遍歷后臺有無包括這種規(guī)格的商品(除了庫存為0)屈嗤;如果沒有則把按鈕變成灰色(即改變狀態(tài))潘拨;讓我們來分析下這種方案的優(yōu)缺點。
尺寸:5.0寸饶号、4.5寸
型號:土豪金铁追、紅、黑
內(nèi)存:128G茫船、64G
后臺可選的規(guī)格:
[
["4.5寸", "紅", "64G"],
["5.0寸", "土豪金", "128G"], //
["5.0寸", "黑", "128G"]
]
????????現(xiàn)在這幾種類型一共有2 * 3 * 2 = 12種排列組合脂信,然而只有3種組合是正確的(其中還要排除庫存為0的情況)一開始先保存好每一個按鈕和每一列的位置進入一個List<List<TagEnable>> 的數(shù)組中癣蟋,TagEnable記錄著每一個按鈕的狀態(tài)(0代表者正常,1代表選中狰闪,2代表不可選(庫存為0||無規(guī)格))疯搅;然后當(dāng)用戶點擊的時候,用Map<Integer,String> 記錄選中的按鈕和文字埋泵;并把每一個按鈕先設(shè)置為不可點擊幔欧,之后根據(jù)文字去對按鈕進行設(shè)置狀態(tài)。
????????這種算法是比較直接的一種實現(xiàn)丽声,但是很繁瑣礁蔗,循環(huán)嵌套循環(huán),可以簡單分析下算法復(fù)雜度雁社,如果sku屬性組合元素的總和數(shù)用m來表示浴井,可選的數(shù)據(jù)的長度是n的話,那么算法的步驟大概是m*n霉撵,這看起來好像不怎么復(fù)雜磺浙;不過,每次判斷一個sku組合是否和result中的 組合匹配徒坡,卻不是一個簡單的過程撕氧,實際上,這可以看做是一個字符串匹配的一個算法了喇完, 最簡單的還是使用正則匹配伦泥,m * n次正則匹配,這樣就不怎么快了吧锦溪。正則表達式很不穩(wěn)定不脯,萬一sku組合中有一些特殊字符,就可能導(dǎo)致一個正則匹配沒能匹配到我們想要的表達式刻诊。
而且防楷,當(dāng)用戶全部選中的時候,根據(jù)這種算法坏逢,只會出現(xiàn)一種情況域帐,就是未選中的全部都變成不可選(即變成灰色)赘被,這大大影響了用戶的體驗是整。如下圖:
????????sku算法是利用數(shù)學(xué)的集合思想來寫的。即先把可能的排列組合列出來民假,即取出集合中的所有子集浮入,數(shù)學(xué)上叫做冪集。
就是如果第一條數(shù)據(jù)["5.0寸", "黑", "128G"]可選羊异,
那么以下的組合肯定存在:
- 5.0寸
- 黑
- 128G
- 5.0寸事秀、黑
- 5.0寸彤断、128G
- 黑、128G
- 5.0寸易迹、黑宰衙、128G
所以,我們可以利用sku算法取出所有的組合睹欲,再根據(jù)這些組合的集合供炼,記為U,去判斷用戶點擊按鈕時窘疮,去設(shè)置其他按鈕的狀態(tài)袋哼;
例如:當(dāng)用戶進行如下的選擇:5.0寸、128G
那么如何判斷 4.5寸這個按鈕的狀態(tài)呢闸衫?只需判斷4.5寸涛贯、128G是否可選(集合U是否存在(4.5寸-128G)這個組合并且?guī)齑娌粸?),以此類推:
4.5寸: U是否包含于 4.5寸-128G false
土豪金: U是否包含于 5.0寸-土豪金-128G true
紅: U是否包含于 5.0寸-紅-128G false
黑: U是否包含于 5.0寸-黑-128G true
64G: U是否包含于 5.0寸-64G false
于是乎蔚出,我們可以得出下列的結(jié)果:
優(yōu)化:
在使用淘寶的過程中弟翘,我發(fā)現(xiàn)他們可以根據(jù)用戶選擇按鈕的唯一值確定圖像(例如在這案例中,顏色是唯一的)身冬,當(dāng)用戶只選擇唯一值時衅胀,便可以確定其圖像
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < mUiData.getAdapters().size(); i++) {
if (mUiData.getAdapters().get(i).getCurrentSelectedItem()!=null)
stringBuilder.append(mUiData.getAdapters().get(i)
.getCurrentSelectedItem().getAttributeMemberId()+";");
}
if (stringBuilder.length()!=0) {
List<String> pricelist = new ArrayList<String>();
for (Map.Entry<String, BaseSkuModel> entry : mUiData.getResult().entrySet()) {
// System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
if (mUiData.getSelectedEntities().size() == 1) {
if (entry.getKey().contains(stringBuilder.toString())) {
pricelist.add(entry.getValue().getPicture());
}
} else {
if (entry.getKey().contains(stringBuilder.substring(0, stringBuilder.length() - 1).toString())) {
pricelist.add(entry.getValue().getPicture());
}
}
}
List<String> newlist = ifRepeat(pricelist);
BaseSkuModel baseSkuModel = new BaseSkuModel();
if (newlist.size() == 1) {
// Toast.makeText(MainActivity.this,""+,Toast.LENGTH_SHORT).show();
baseSkuModel.setPicture(newlist.get(0));
baseSkuModel.setPrice(mUiData.getBaseSkuModel().getPrice());
baseSkuModel.setFormatNum(mUiData.getBaseSkuModel().getFormatNum());
baseSkuModel.setStock(mUiData.getBaseSkuModel().getStock());
} else {
baseSkuModel = mUiData.getBaseSkuModel();
}
mUiData.setCurrentskumodel(baseSkuModel);
}else{
mUiData.setCurrentskumodel(mUiData.getBaseSkuModel());
}
做法是這樣子的:先遍歷原始數(shù)據(jù),如果用戶選擇的組合在原數(shù)據(jù)中是唯一的話酥筝,則可以確定其圖像滚躯。