应用排列生成 table

Apply permutation to generate a table

我有以下键值对,我需要根据键找到所有组合。在图中,第一个 table 显示所有键值对,第二个 table 显示预期输出的摘录。所有可能的组合都应该是table。

public ActionResult ViewSystemValues ()
{
    var model = new List<ViewSystemValuesVM>();//Each item in Model consists of the Key Value pair mentioned in the question         
    var tclist = new List<TcSet>(); //Each item is the link to the Property that holds the key
    var tcid = new List<int>(); //List of distinct keys in tclist              

    //For simplicity I have eliminated the code that would populate the Lists  and the model with the description as comments

    string[] myArray = new string[tclist.Count()];
    var model1 = new List<String[]>();
    int tclistcount = tclist.Count();
    foreach(var x in model)
    {
        foreach (var item in model)
        for(int i=0;i<tclistcount;i++)
        {         
            if (tcid[i] == item.TcSetID)
                myArray[i] = item.Value; 
        }
        model1.Add(myArray);
    }
}

接近

myArray 对应于我排列的 table 中的一行。 model 持有有效的键值对。我检查 modeltcid 中的键是否相同,可以将值添加到 myArray 中,索引与 tcid 相同,以便我得到相应的值tcid

但我只得到最后可能的组合

colour  fruit    vegatable
yellow  banana    beans 
yellow  banana    beans 
yellow  banana    beans 
yellow  banana    beans 
yellow  banana    beans 
yellow  banana    beans 

这是你想要的吗?

Func<string[][], string[][]> build = null;
build = s =>
    s.Length == 1
        ? s[0].Select(x => new [] { x }).ToArray()
        : build(s.Skip(1).ToArray())
            .SelectMany(xs => s[0].Select(x => new [] { x }.Concat(xs).ToArray()))
            .ToArray();

此查询中的基本情况,当 s.Length == 1 基本上将 new [] { new [] { "onion", "potato", "tomato", "beans" } } 变成 new [] { new [] { "onion", }, new [] { "potato", }, new [] { "tomato", }, new [] { "beans", }, }。非基本情况递归调用 build 然后将第一个数组的值附加到每个递归数组的开头。很高兴你问了?

或者我可以这样写这个查询:

Func<string[][], string[][]> build = null;
build = s =>
(
    s.Length == 1
        ? from x in s[0] select new [] { x }
        : from xs in build(s.Skip(1).ToArray())
          from x in s[0] select new [] { x }.Concat(xs).ToArray()
).ToArray();

这可能会帮助您更轻松地分解它。

如果我从这个数据开始:

var source = new []
{
    new { Key = "colour", Value = "red", },
    new { Key = "colour", Value = "blue", },
    new { Key = "colour", Value = "violet", },
    new { Key = "colour", Value = "black", },
    new { Key = "colour", Value = "yellow", },
    new { Key = "fruit", Value = "apple", },
    new { Key = "fruit", Value = "mango", },
    new { Key = "fruit", Value = "banana", },
    new { Key = "vegetable", Value = "onion", },
    new { Key = "vegetable", Value = "potato", },
    new { Key = "vegetable", Value = "tomato", },
    new { Key = "vegetable", Value = "beans", },
};

string[][] data =
    source
        .ToLookup(x => x.Key, x => x.Value)
        .Select(x => x.ToArray())
        .ToArray();

我得到这个结果:

new []
{
   new [] { "red", "apple", "onion" } 
   new [] { "blue", "apple", "onion" } 
   new [] { "violet", "apple", "onion" } 
   new [] { "black", "apple", "onion" } 
   new [] { "yellow", "apple", "onion" } 
   new [] { "red", "mango", "onion" } 
   new [] { "blue", "mango", "onion" } 
   new [] { "violet", "mango", "onion" } 
   new [] { "black", "mango", "onion" } 
   new [] { "yellow", "mango", "onion" } 
   new [] { "red", "banana", "onion" } 
   new [] { "blue", "banana", "onion" } 
   new [] { "violet", "banana", "onion" } 
   new [] { "black", "banana", "onion" } 
   new [] { "yellow", "banana", "onion" } 
   new [] { "red", "apple", "potato" } 
   new [] { "blue", "apple", "potato" } 
   new [] { "violet", "apple", "potato" } 
   new [] { "black", "apple", "potato" } 
   new [] { "yellow", "apple", "potato" } 
   new [] { "red", "mango", "potato" } 
   new [] { "blue", "mango", "potato" } 
   new [] { "violet", "mango", "potato" } 
   new [] { "black", "mango", "potato" } 
   new [] { "yellow", "mango", "potato" } 
   new [] { "red", "banana", "potato" } 
   new [] { "blue", "banana", "potato" } 
   new [] { "violet", "banana", "potato" } 
   new [] { "black", "banana", "potato" } 
   new [] { "yellow", "banana", "potato" } 
   new [] { "red", "apple", "tomato" } 
   new [] { "blue", "apple", "tomato" } 
   new [] { "violet", "apple", "tomato" } 
   new [] { "black", "apple", "tomato" } 
   new [] { "yellow", "apple", "tomato" } 
   new [] { "red", "mango", "tomato" } 
   new [] { "blue", "mango", "tomato" } 
   new [] { "violet", "mango", "tomato" } 
   new [] { "black", "mango", "tomato" } 
   new [] { "yellow", "mango", "tomato" } 
   new [] { "red", "banana", "tomato" } 
   new [] { "blue", "banana", "tomato" } 
   new [] { "violet", "banana", "tomato" } 
   new [] { "black", "banana", "tomato" } 
   new [] { "yellow", "banana", "tomato" } 
   new [] { "red", "apple", "beans" } 
   new [] { "blue", "apple", "beans" } 
   new [] { "violet", "apple", "beans" } 
   new [] { "black", "apple", "beans" } 
   new [] { "yellow", "apple", "beans" } 
   new [] { "red", "mango", "beans" } 
   new [] { "blue", "mango", "beans" } 
   new [] { "violet", "mango", "beans" } 
   new [] { "black", "mango", "beans" } 
   new [] { "yellow", "mango", "beans" } 
   new [] { "red", "banana", "beans" } 
   new [] { "blue", "banana", "beans" } 
   new [] { "violet", "banana", "beans" } 
   new [] { "black", "banana", "beans" } 
   new [] { "yellow", "banana", "beans" } 
}

这适用于任意数量的键。

试试这个数据:

var source = new []
{
    new { Key = "colour", Value = "red", },
    new { Key = "fruit", Value = "apple", },
    new { Key = "vegetable", Value = "onion", },
    new { Key = "nation", Value = "france", },
    new { Key = "nation", Value = "australia", },
};

我得到这个结果:

new []
{
   new [] { "red", "apple", "onion", "france" } 
   new [] { "red", "apple", "onion", "australia" } 
}

如果您的密钥是 int 那么代码的工作原理是一样的:

var source = new[]
{
    new { Key = 1, Value = "red", },
    new { Key = 1, Value = "apple", },
    new { Key = 2, Value = "onion", },
    new { Key = 3, Value = "france", },
    new { Key = 3, Value = "australia", },
};

string[][] data =
    source
        .ToLookup(x => x.Key, x => x.Value)
        .Select(x => x.ToArray())
        .ToArray();

Func<string[][], string[][]> build = null;
build = s =>
(
    s.Length == 1
        ? from x in s[0] select new[] { x }
        : from xs in build(s.Skip(1).ToArray())
          from x in s[0]
          select new[] { x }.Concat(xs).ToArray()
).ToArray();

这是 build 的非匿名版本:

public string[][] Build(string[][] source)
{
    return
    (
        source.Length == 1
            ? from x in source[0] select new[] { x }
            : from xs in Build(source.Skip(1).ToArray())
              from x in source[0]
              select new[] { x }.Concat(xs).ToArray()
    ).ToArray();
}

这不是问题的真正答案。但是当变量数量固定时可以遵循的方法。这种方法可以扩展到可变输入

   public ActionResult tablecreate()
    {
        string[] key = { "colour", "fruit", "vegetable" };
        var kvpair = new List<Tuple<String,String>>();
        kvpair.Add(new Tuple<String,String>("colour","red"));
        kvpair.Add(new Tuple<String, String>("colour", "blue"));
        kvpair.Add(new Tuple<String, String>("colour", "yellow"));
        kvpair.Add(new Tuple<String, String>("colour", "black"));
        kvpair.Add(new Tuple<String, String>("fruit", "mango"));
        kvpair.Add(new Tuple<String, String>("fruit", "apple"));
        kvpair.Add(new Tuple<String, String>("vegetable", "potato"));
        kvpair.Add(new Tuple<String, String>("vegetable", "tomato"));
        kvpair.Add(new Tuple<String, String>("vegetable", "beans"));
        var combi = new List<Tuple<String,String,String>>();
        int i = 0, j = 0, k = 0;
        var colorval = new List<String>();
        var fruitval = new List<String>();
        var vegval =new List<String>();
        foreach (var item in kvpair)
        {
            if (item.Item1 == "colour")
                colorval.Add(item.Item2);
            else if (item.Item1 == "fruit")
                fruitval.Add(item.Item2);
            else if (item.Item1 == "vegetable")
                vegval.Add(item.Item2);
        }
        foreach(var col in colorval)
        {
            foreach(var fru in fruitval)
            {
                foreach(var veg in vegval)
                {
                    combi.Add(new Tuple<string, string, string>(col, fru, veg));
                }
            }
        }

输出将生成问题中提到的table

我可以使用以下代码获取属于每个键的值,但仍然缺少组合

  var serialize = new List<Tuple<int, List<string>>>();

 for(int i=0;i<tcid.Count();i++)
 {
       var val = new List<string>();
       foreach(var item in model)
       {
           if(tcid[i]==item.TcSetID)
                val.Add(item.Value);        
       }
       serialize.Add(new Tuple<int,List<string>>(tcid[i],val));
  }

现在在 serailize 中,我们拥有每个键的所有可能值。

为了更清楚,serailize 仅用作变量名。 serailise 列表类似于上面代码中的 colorvalfruitvalvegval,具有常量变量。

因此 serailize 将保存如下值:

serialize [item1 :colour, item2 : {blue,red,black,yellow}]
serialize [item1 :fruit, item2 : {apple,mango}]
serialize [item1 :vegetable, item2 : {tomato,potato,beans}]

我有一个函数可以计算 serialize.item2

中两项的笛卡尔积
public List<String> Cartesian (List<String> A, List<String> B)
{
    int Alenght = A.Count();
    int Blength = B.Count();
    var S = new List<String>();
    for (int i = 0; i < Alenght;i++ )
    {
       for(int j=0;j<Blength;j++)
       {
           S.Add(A[i] + "delim" + B[j]);
       }
    }
    return S;
}

函数调用如下

 var A = new List<String>();
 foreach(var item in serialize)
 {
     if(j==0)
     {
         A = item.Item2;
         j = 1;    
     }
     else
         A =  Cartesian(A, item.Item2);
  }

然后将列表A中的字符串作为字符串数组

 //distinctlist contains all the distinct strings in A
 foreach(var item in distinctlist)
 {
     var row = new ViewsVM();
     row.row = item.Split(new string[] { "delim"},StringSplitOptions.None);
     ViewsVM.Add(row);
 }

ViewsVM

public class ViewsVM
{ 
    public string[] row  { get; set; }
}

希望对大家有所帮助。但我应该警告这不是最好的方法。

Enigmativity 有更好的方法来解决这个问题。我发布这个答案只是因为我也找到了一个替代方法来做到这一点。