从递归函数

时间:2015-11-04 19:04:23

标签: f#

我正在尝试从函数中返回一个列表,但是我收到一条错误消息,指出单位是预期的。另外,我想知道这段代码的结构是否正确。

代码:

    let rec calculateVariants (attList: NewProductAttributeInfo list) (activeCount: int) 
    (currentList: (int * NewProductAttributeInfo) list) =

    // group attribute list by category id
    let attGrouped = attList |> List.groupBy (fun x -> x.AttributeCategoryId)

    // define mutable list
    let mutable stageList = currentList

    // begin iteration
    for catId,details in attGrouped do
        for d in details do
            if activeCount = 0
            then stageList <- (activeCount,d) :: stageList

            let groupLength = attGrouped.Length
            if (activeCount + 1) <= groupLength
            then
                let selectCat,selectDetails = attGrouped.[activeCount + 1]
                selectDetails
                    |> List.filter (fun x -> 
                        stageList
                        |> List.exists (fun (x') -> 
                            not(x' = (activeCount,x))))
                    |> (fun x ->
                        match x with
                        | [] -> ()
                        | head :: tail -> 
                            stageList <- (activeCount, head) :: stageList
                            let currentCategory = activeCount + 1
                            calculateVariants attList currentCategory stageList
                            )
    stageList // <-- error Unit expected

2 个答案:

答案 0 :(得分:2)

if .. then .. else应该在两个分支上返回相同的类型。如果省略else分支,则编译器假定它返回unit。添加else分支返回列表。

修改 鉴于您的问题描述,最简单的方法是这样的:

type NewProductAttributeInfo = {AttributeCategoryId: string; AttributeId: string}
let products = [ { AttributeCategoryId = "Size"; AttributeId = "S"};
                 { AttributeCategoryId = "Mat"; AttributeId = "Linen" };
                 { AttributeCategoryId = "Mat"; AttributeId = "Poliester" };
                 { AttributeCategoryId = "Color"; AttributeId = "White" };
                 { AttributeCategoryId = "Color"; AttributeId = "Green" };
                 { AttributeCategoryId = "Mat"; AttributeId = "Linen" };
                 { AttributeCategoryId = "Mat"; AttributeId = "Cotton" };
                 { AttributeCategoryId = "Mat"; AttributeId = "Poliester" };
                 { AttributeCategoryId = "Size"; AttributeId = "XL" } ]

let group list =
    list 
    |> Set.ofList // Provides uniqueness of attribute combinations
    |> Seq.groupBy (fun x -> x.AttributeCategoryId) // Grouping by CatId
    |> List.ofSeq

let res = group products

结果:

val it : (string * seq<NewProductAttributeInfo>) list =
 [("Color", seq [{AttributeCategoryId = "Color";
                  AttributeId = "Green";}; {AttributeCategoryId = "Color";
                                            AttributeId "White";}]);
  ("Mat",
   seq
     [{AttributeCategoryId = "Mat";
       AttributeId = "Cotton";}; {AttributeCategoryId = "Mat";
                                  AttributeId = "Linen";};
      {AttributeCategoryId = "Mat";
       AttributeId = "Poliester";}]);
  ("Size", seq [{AttributeCategoryId = "Size";
                 AttributeId = "S";}; {AttributeCategoryId = "Size";
                                       AttributeId = "XL";}])]

答案 1 :(得分:0)

这是我带来的解决方案。它有效,但我确信它可以进行相当多的优化。我有一个重复的问题,在此代码运行后使用外部的Set.ofList函数解决,我仍在努力。

type NewProductAttributeInfo = {
    AttributeId : string;
    AttributeCategoryId : string
}


let rec private returnVariant (curIdx: int) (listLength: int) 
    (attList: (int * NewProductAttributeInfo * NewProductAttributeInfo) list) 
    (curList: NewProductAttributeInfo list) =

    match curList with
    | x when x.Length = listLength -> curList
    | x -> 
        let attTup =
            attList
            |> List.filter (fun x' -> 
                                let idx1,att1,att2' = x'
                                idx1 >= curIdx && not(curList 
                                                        |> List.exists (fun x'' -> 
                                                                            x'' = att2'))
                            )
        let idx1,att1,att2 = attTup |> List.head
        let newList = curList @ [att2]
        returnVariant idx1 newList.Length attList newList


let rec calculateVariants (attList: NewProductAttributeInfo list) 
    (currentList: (int * NewProductAttributeInfo * NewProductAttributeInfo) list) =

    // group attribute list by category id
    let attGrouped = attList |> List.groupBy (fun x -> x.AttributeCategoryId)
    let (firstGroupCatId,firstGroupDetails) = attGrouped.[0]




    match currentList with
    | [] ->
        let rawVariants = [for nxt in 0 .. (attGrouped.Length - 1) do
                            if nxt > 0
                            then
                                // begin iteration
                                for d in firstGroupDetails do
                                    let _,det = attGrouped.[nxt]
                                    for det' in det do
                                        yield (nxt, d, det')
                        ]
        calculateVariants attList rawVariants
    | x ->
        let groupLength = x |> List.groupBy (fun (idx,d0,nxtD) -> idx)
                        |> List.length |> ((+)1)
        let sortedGroup = x |> List.sortBy (fun (x,y,z) -> x)
        if groupLength > 2
        then // below is the block that generates the duplicates
            [for att in sortedGroup do
                for attCompare in sortedGroup do
                    let idx1,att1,att2 = att
                    let idx2,attC1,attC2 = attCompare
                    if idx2 > idx1 && att2 <> attC2
                    then
                        let idString = 
                            returnVariant idx2 groupLength x [att1; att2; attC2]
                            |> List.map (fun nl -> nl.AttributeId)
                        yield String.concat "," idString
            ]
        else
            [
                for att in sortedGroup do
                    let idx1,att1,att2 = att
                    let idString = 
                            returnVariant idx1 groupLength x [att1; att2]
                            |> List.map (fun nl -> nl.AttributeId)
                    yield String.concat "," idString
            ]