首页 > 技术文章 > 有趣的Linq

prozhou 2014-06-02 23:44 原文

  由于无聊透顶的童年生活和无趣的学生时代的阴影,让我对一些逻辑小问题充满了兴趣。就像下面这个题目:

  有ABCD四个人,A说:B偷吃了苹果,B说:是D吃的,C说:不是我,D说:B说谎。现在已知条件为:这四个人中,只有一个人说的是真话。请问:偷吃了苹果的人到底是谁?

  其实不用说也知道,这题肯定是有瑕疵的,它的问题是“偷吃了苹果的到底是谁?”,这个谁是否在暗示我们偷吃苹果的只有一个人,会不会有多人瓜分的情况?这个题目直接限死了一人偷吃苹果的隐含条件了(稍后我们可以证明)。

  兴趣归兴趣,我解答这类问题实在是不太聪明,每次都容易把自己绕进去。包括现在的写程序有时也是一样,如果处理的逻辑复杂,就把自己绕进去了。因此,我对Linq这种语法糖特别有好感。

  “那么这个问题用Linq怎么解决?”我突然提起了兴趣。

  马上,就我就反应过来,这题主要包括两个条件,一个是讲真话,一个是偷吃苹果;所以我可以建一个类,就叫它People吧:

  

    class People
    {
        //代表是否偷吃
        public bool Eat { get; set; }
        //代表是否讲真话
        public bool SayTruth { get; set; }
    }

  这四个人中,所有的可能性只有四种,即:说真话,偷吃;说假话,偷吃;说真话,没偷吃;说假话,没偷吃。所以就有:

 

List<People> peopleList = new List<People>
{
    new People{Eat = true,SayTruth = true},
    new People{Eat = true,SayTruth = false},
    new People{Eat = false,SayTruth = true},
    new People{Eat = false,SayTruth = false},
}

  四个人A,B,C,D只有这四种情况,而且有两个很明显的限制条件,即:有且仅有一个人说真话;有且仅有一个人偷吃苹果:

        private static bool confirmOnlyOne(List<People> allPeople)
        {
            if (allPeople.Where(x => x.SayTruth == true).Count() == 1 && allPeople.Where(x => x.Eat == true).Count() == 1)
                return true;
            else return false;
        }

 

  接下来就是主要的Linq语句了,根据题中的条件,可以很容易地写出如下拙劣的Linq语句并输出结果:

            var query = from A in peopleList
                        from B in peopleList
                        from C in peopleList
                        from D in peopleList
                        where confirmOnlyOne(new List<People> { A, B, C, D }) && A.SayTruth == B.Eat && D.Eat == B.SayTruth && !C.Eat == C.SayTruth && D.SayTruth == !B.SayTruth
                        select new
                        {
                            A,B,C,D
                        };

            foreach (var item in query)
            {
                Console.WriteLine("A: Eat-{0},SayTruth-{1}", item.A.Eat, item.A.SayTruth);
                Console.WriteLine("B: Eat-{0},SayTruth-{1}", item.B.Eat, item.B.SayTruth);
                Console.WriteLine("C: Eat-{0},SayTruth-{1}", item.C.Eat, item.C.SayTruth);
                Console.WriteLine("D: Eat-{0},SayTruth-{1}", item.D.Eat, item.D.SayTruth);
            }


其结果为:

很明显,偷吃苹果的是C,说真话的是D!Kid's Stuff!!

PS: 那么,如果我们不顾“只有一个人偷吃苹果”这一隐藏条件的话会怎么样呢?我试了一下,果然有多条结果,所以……该出题人已经假定了只有一个人偷吃了苹果,他应该做的是把话说得更明白一些。

 

 

 

 

推荐阅读