我正在開發一個庫存管理系統,我想添加一個帶有變體的產品。我可以添加具有三種變體(顏色、尺寸、材料)的產品,每種產品的選項如下:
顏色 - 黑色、藍色、灰色 尺寸 - S、M、L、XL 材質 - 棉、羊毛
如果僅指定 2 個變體(例如顏色和大小),我的代碼會正確生成所有選項,但如果我添加第 3 個變體,那么它不會給我預期的輸出。
假設我有一個名為 Jean 的產品,我的預期輸出如下:
- 讓-布萊克/S/棉
- 讓-布萊克/S/羊毛
- 讓-布萊克/M/棉
- 讓-布萊克/M/羊毛
- 讓-布萊克/L/棉
- Jean-Black/L/羊毛
- Jean-Black/XL/棉
- Jean-Black/XL/羊毛
============================================
- 牛仔藍/S/棉
- 牛仔藍/S/羊毛
- 讓-藍/M/棉
- 牛仔藍/M/羊毛
- 牛仔藍/L/棉
- 牛仔藍/L/羊毛
- 牛仔藍/XL/棉
- 牛仔藍/XL/羊毛
============================================
- 讓-格雷/S/棉
- 讓-格雷/S/羊毛
- 讓-格雷/M/棉
- 讓-格雷/M/羊毛
- 讓-格雷/L/棉
- 讓-格雷/L/羊毛
- 讓-格雷/XL/棉
- 讓-格雷/XL/羊毛
我的模型如下:
public class CreateModel : PageModel
{
[Required]
[BindProperty]
public string? Name { get; set; }
[BindProperty]
public List<ProductVariantModel> Variants { get; set; }
}

產品變體模型
public class ProductVariantModel
{
public string? Name { get; set; }
public string? Options { get; set; }
}
我正在創建如下組合:
List<ProductVariantOption> productOptions = new();
try
{
int variantsTotal = model.Variants.Count;
for (int a = 0; a < variantsTotal; a )
{
string[] options = model.Variants[a].Options.Split(',');
for (int i = 0; i < options.Length; i )
{
string? option = $"{model.Name}-{options[i]}";
if (variantsTotal > 1)
{
int index = a 1;
if (index < variantsTotal)
{
var levelBelowOptions = model.Variants[index].Options.Split(',');
var ops = GetOptions(option, levelBelowOptions);
productOptions.AddRange(ops);
}
}
}
a = 1;
}
}
獲取選項方法
private List<ProductVariantOption> GetOptions(string option, string[] options)
{
List<ProductVariantOption> variantOptions = new();
for (int i = 0; i < options.Length; i )
{
string sku = $"{option}/{options[i]}";
string opt = $"{option}/{options[i]}";
variantOptions.Add(new ProductVariantOption(opt, sku));
}
return variantOptions;
}
產品變體選項
public class ProductVariantOption
{
public string Name { get; private set; }
public string SKU { get; private set; }
public Guid ProductVariantId { get; private set; }
public ProductVariant ProductVariant { get; private set; }
public ProductVariantOption(string name, string sku)
{
Guard.AgainstNullOrEmpty(name, nameof(name));
Name = name;
SKU = sku;
}
}
我在哪里弄錯了?
uj5u.com熱心網友回復:
如果你概括你的問題,你可以描述如下:
- 對于以單個變體(基本模型名稱)開頭的模型的每個潛在變數,使用此變數生成迄今為止所有可能的模型組合
- 生成這些組合后,將每個生成的組合映射到 ProductVariantOption。
因此,您可能希望生成所有變數串列的叉積。這可以通過.Aggregatewhich does .SelectManyinside 來實作(請注意,我已經簡化了最終輸出的定義,但是您可以在.BuildModel方法中根據需要構建它:
private static ProductVariantOption BuildModel(string[] modelParts) {
if (modelParts.Length == 1) {
return new ProductVariantOption {
Name = modelParts.Single()
};
}
var baseName = modelParts.First();
var variantParts = string.Join('/', modelParts.Skip(1));
return new ProductVariantOption {
Name = $"{baseName}-{variantParts}"
};
}
public static IList<ProductVariantOption> GetVariants(CreateModel model) {
// Prepare all possible variables from the model in advance
var allVariables = model.Variants.Select(v => v.Options.Split(",")).ToArray();
var initialParts = new List<string[]> { new[] { model.Name } };
// Generate cross product for every subsequent variant with initial list as a seed
// Every iteration of aggregate produces all possible combination of models with the new variant
var allModels = allVariables.Aggregate(initialParts, (variantsSoFar, variableValues) =>
variantsSoFar
.SelectMany(variant => variableValues.Select(variableValue => variant.Append(variableValue).ToArray()))
.ToList()
);
// Map all lists of model parts into ProductVariantOption
return allModels.Select(BuildModel).ToList();
}
這種方法的好處是能夠處理任何數量的潛在變數,包括沒有變數的情況(在這種情況下,只產生一個變體 - 在你的例子中,它只是“Jean”)
完整運行示例: https ://dotnetfiddle.net/XvkPZQ
uj5u.com熱心網友回復:
我不確定為什么你的name和SKU欄位相同,但是使用你的模型,你需要初始化一個第一級產品變體的串列,然后使用該串列作為產品變體,并將下一個變體添加到每個產品變體在串列中。
List<string>到目前為止,我只是使用 a來存盤名稱,并向其中添加了每個變體的選項:
var productVariantsName = model.Variants[0].Options.Split(',')
.Select(o => $"{model.Name}-{o}")
.ToList();
foreach (var variant in model.Variants.Skip(1)) {
var pvNameSoFar = productVariantsName;
productVariantsName = new();
foreach (var pvName in pvNameSoFar) {
foreach (var option in variant.Options.Split(','))
productVariantsName.Add($"{pvName}/{option}");
}
}
var productOptions = productVariantsName
.Select(pvName => new ProductVariantOption(pvName, pvName))
.ToList();
您也可以使用答案中的CartesianProduct LINQ 方法使用 LINQ 執行此操作(我使用稍微不同的 lambda 版本)。
有了這個定義,您可以執行以下操作:
var productOptions = model.Variants
.Select(v => v.Options.Split(','))
.CartesianProduct()
.Select(vs => $"{model.Name}-{vs.Join("/")}")
.Select(pvName => new ProductVariantOption(pvName, pvName))
.ToList();
PS:這使用了Join字串擴展方法的明顯定義。
為了完整起見,以下是使用的擴展:
public static class IEnumerableExt {
public static string Join(this IEnumerable<string> ss, string sep) => String.Join(sep, ss);
public static IEnumerable<T> AsSingleton<T>(this T item) => new[] { item };
// ref: https://stackoverflow.com/a/3098381/2557128
public static IEnumerable<IEnumerable<T>> CartesianProduct<T>(this IEnumerable<IEnumerable<T>> sequences) =>
sequences.Aggregate(Enumerable.Empty<T>().AsSingleton(),
(accumulator, sequence) => accumulator.SelectMany(_ => sequence,
(accseq, item) => accseq.Append(item)));
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/492627.html
標籤:C# 循环 asp.net 核心 for循环 嵌套循环
下一篇:For回圈在R中繪制多個變數
