根据c#列表中的位置创建组合

时间:2018-06-27 02:15:57

标签: c# list linq

我有一个清单

    var list = new List<record>{
    new record{ flashid = 450, position = 5, value = "a"},
    new record{ flashid = 450, position = 6, value = "b"},
    new record{ flashid = 450, position = 7, value = "c"},
    new record{ flashid = 450, position = 7, value = "d"},
    new record{ flashid = 450, position = 7, value = "e"},
    new record{ flashid = 450, position = 8, value = "f"},
    new record{ flashid = 450, position = 9, value = "g"}
}

我有3个记录,其位置分别为7和7。从上面的列表中,我需要根据1到10的位置为每个组合创建一个字符串。对于丢失的位置值,我们可以使用任何临时字符。 因此,所需的输出将是

["....abcfg.","....abdfg.","....abefg."]

我们可以在点号处使用任何特殊字符。

谢谢

2 个答案:

答案 0 :(得分:2)

当然,您可以解决此问题,如注释到问题的链接中所述,但是,在这种情况下,您应该做繁琐的工作-编写很多可重复的代码,例如:

var answer = (from pos1 in list.Where(x => x.position == 1)
              from pos2 in list.Where(x => x.position == 2)
              from pos3 in list.Where(x => x.position == 3)
              ....
              from pos10 in list.Where(x => x.position == 10)
              select pos1.value + pos2.value + pos3.value + ... + pos10.value
             ).ToList();

因此,每次需要更改可能位置的数量时,都应添加或删除相应的代码行。相反,您可以尝试recursive approach。前一个解决方案不是动态的-您应该在编译时预先知道位置数,而第二个解决方案可以在运行时通过limit变量更改来简单地调整。

static int limit = 10;

static void Recursive(record record, List<string> bag, 
    Stack<record> stack, List<record> list)
{
    stack.Push(record);
    if (record.position == limit)
    {
        var temp = new StringBuilder();
        foreach (var item in stack)
            temp.Insert(0, item.value);
        bag.Add(temp.ToString());
    }
    else            
        foreach (var item in list.Where(x => x.position == record.position + 1))
            Recursive(item, bag, stack, list);
    stack.Pop();            
}

static List<string> Solve(List<record> list)
{
    for (var i = 1; i <= limit; i++)
        if (!list.Any(x => x.position == i))
             list.Add(new record { position = i, value = "." });

    var bag = new List<string>();
    var stack = new Stack<record>();
    foreach (var record in list.Where(x => x.position == 1))
        Recursive(record, bag, stack, list);

    return bag;
}

用法:

var list = new List<record>
{
    new record { flashid = 450, position = 5, value = "a"},
    new record { flashid = 450, position = 6, value = "b"},
    new record { flashid = 450, position = 7, value = "c"},
    new record { flashid = 450, position = 7, value = "d"},
    new record { flashid = 450, position = 7, value = "e"},
    new record { flashid = 450, position = 8, value = "f"},
    new record { flashid = 450, position = 9, value = "g"}
};

var answer = Solve(list);       
Console.WriteLine("[" + string.Join(", ", answer) + "]");       
//output: [....abcfg., ....abdfg., ....abefg.]

答案 1 :(得分:0)

如果您想使用纯LINQ解决方案,可以尝试以下方法。首先扩展您的记录列表,使其包含每个丢失的职位:

var extendedList = Enumerable
    .Range(1, 10)
    .GroupJoin(list, n => n, r => r.position, (n, g) => g
        .DefaultIfEmpty(new record { flashid = 450, position = n, value = "." }));

基本上,范围是1到10,并且对应于位置匹配和分组记录的每个数字。如果组中不包含任何匹配值,则表示缺少位置时,将创建带有临时字符的默认记录。所以结果看起来像这样:

record[10][] 
{ 
    record[] 
    { 
        record { flashid=450, position=1, value="." } 
    },
    (...)
    record[] 
    { 
        record { flashid=450, position=5, value="a" } 
    },
    (...)
    record[] 
    { 
        record { flashid=450, position=7, value="c" },
        record { flashid=450, position=7, value="d" },
        record { flashid=450, position=7, value="e" } 
    },
    (...)
},

现在要生成所有可能的值,您可以尝试以下操作:

var result = extendedList
    .Aggregate(Enumerable.Repeat("", 1), (a, c) => a
        .SelectMany(b => c
            .Select(d => b + d.value)));

每个Aggregate迭代将单词序列转换为在当前位置的字符组中添加了单个字符的另一个单词序列。就像这样:

0. {""}
1. {"."}
2. {"."}
3. {".."}
4. {"..."}
5. {"....a"}
6. {"....ab"}
7. {"....abc", "....abd", "....abe"}
8. {"....abcf", "....abdf", "....abef"}
9. {"....abcfg", "....abdfg", "....abefg"}
10. {"....abcfg.", "....abdfg.", "....abefg."}

您可以在这里尝试:https://dotnetfiddle.net/JCgYFP

相关问题