如何将列表与优先级相结合

时间:2017-05-31 08:04:55

标签: c# algorithm list operator-precedence

我有一个像这样的字符串列表:

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 });

我想使用ANDOr中的AND和OR从这4个列表中创建一个新列表。由于AND的优先级高于OR优先级,因此我将应用AND,因此我将使用这些:

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

最后结合这两个临时表,因为有一个OR:

var resulList = tempList1.Union(tempList2);

正如您所看到的,当有定义数量的列表和定义的AND和OR数时,可以手动执行此操作。但是当有n个要组合的列表和n-1个AND和OR数时,我无法以编程方式弄清楚如何进行编程。你能帮帮我吗?感谢。

2 个答案:

答案 0 :(得分:4)

我建议将执行分成两个阶段:

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

E.g。

   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 :(得分: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,相反的顺序并不是必需的,但是可以使用单个变量进行迭代。