2017-05-31 49 views
4

我有一个字符串像这样的列表:如何列出关于相结合,优先

List<string> andOrList = new List<string>(); 
andOrList.Add("AND"); 
andOrList.Add("OR"); 
andOrList.Add("AND"); 

而且我有4所列出结合:

List<int> list1 = new List<int>(new int[] { 19, 23, 29 }); 
List<int> list2 = new List<int>(new int[] { 1, 4, 29 }); 
List<int> list3 = new List<int>(new int[] { 1, 5, 23 }); 
List<int> list4 = new List<int>(new int[] { 2, 4, 19 }); 

我想打从一个新的列表这4个列表使用来自andOrList的AND和OR。由于AND的优先级高于OR第一我会申请与运算所以我有这些:

var tempList1 = list1.Intersect(list2).ToList(); 
    var tempList2 = list3.Intersect(list4).ToList(); 

最后结合这两种templists因为有一个OR:

var resulList = tempList1.Union(tempList2); 

正如你可以看到它的可能当有定义数量的列表和已定义的AND和OR的数量时,可以手动完成此操作。但是我不知道如何以编程的方式做到这一点,当有n个列表组合和n-1个AND和OR时。你能帮助我吗?谢谢。

+0

我认为你将不得不编写一种运算符优先级解析器。 – aloisdg

+0

@aloisdg逆向波浪符号的不同版本? – jason

+0

你可以依赖RPN,但它不是必须的 – aloisdg

回答

4

我建议拆分成执行阶段:

1. Performs all `AND`s 
2. Perform all `OR`s 

例如

a & b & c | d | e & f & g | h ==  // put the right order 
    (a & b & c) | (d) | (e & f & g) | (h) == // perform ANDs 
    a_b_c | d | e_f_g | h ==    // perform ORs 
    final result 
你的情况

{19, 23, 29} & {1, 4, 29} | {1, 5, 23} & {2, 4, 19} ==  // put the right order 
    ({19, 23, 29} & {1, 4, 29}) | ({1, 5, 23} & {2, 4, 19}) == // perform ANDs 
    {29} | {} ==            // perform ORs 
    {29} 

实施

private static IEnumerable<T> CombinatorOrAnd<T>(IEnumerable<IEnumerable<T>> sources, 
               IEnumerable<string> actions) { 
    List<IEnumerable<T>> orList = new List<IEnumerable<T>>(); 

    // First, do all ANDs 

    bool isFirst = true; 
    IEnumerable<T> temp = null; 

    using (var en = actions.GetEnumerator()) { 
    foreach (var argument in sources) { 
     if (isFirst) { 
     temp = argument; 
     isFirst = false; 

     continue; 
     } 

     en.MoveNext(); 

     if (en.Current == "AND") 
     temp = temp.Intersect(argument); 
     else { 
     orList.Add(temp); 

     temp = argument; 
     } 
    } 
    } 

    orList.Add(temp); 

    // Finally, perform all ORs 
    return orList.Aggregate((s, a) => s.Union(a)); 
} 

测试

List<int> list1 = new List<int>(new int[] { 19, 23, 29 }); 
    List<int> list2 = new List<int>(new int[] { 1, 4, 29 }); 
    List<int> list3 = new List<int>(new int[] { 1, 5, 23 }); 
    List<int> list4 = new List<int>(new int[] { 2, 4, 19 }); 

    List<string> andOrList = new List<string>(); 
    andOrList.Add("AND"); 
    andOrList.Add("OR"); 
    andOrList.Add("AND"); 

    var result = CombinatorOrAnd(new List<int>[] { list1, list2, list3, list4}, andOrList); 

    Console.Write(string.Join(", ", result.OrderBy(item => item))); 

成果

29 
1

道歉为迟来的答案,但我有这在后台打开。这个想法几乎是一样的:首先执行AND,但是通过变更(复制)输入列表来做到这一点。

public static IEnumerable<int> ProcessAndOr(List<string> andOrList, params List<int>[] Input) 
{ 
    var lst = new List<IEnumerable<int>>(Input); 
    for(int i = andOrList.Count -1 ; i >= 0 ; i--) 
     if(andOrList[i] == "AND") 
     { 
      lst[i] = lst[i].Intersect(lst[++i]); 
      lst.RemoveAt(i--); 
     } 
    return lst.SelectMany(l=>l).Distinct(); 
} 

的例子可以用var resultList = ProcessAndOr(andOrList, list1,list2,list3,list4);调用和产生29

PS,相反的顺序是不是真的有必要,但做是为了能够使用单个变量进行迭代。