Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people, just like you, are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
Solved

LINQ Query

Posted on 2011-09-16
9
353 Views
Last Modified: 2013-11-11
I can't seem to wrap my brain around what strikes me as very simple.

Assume I have these two simple tables (IEnumerables really)

Table1: Authorities (IEnumerable<AuthorityRow>)
Position     CanAuthorize
======================
CEO           MedicalTravel
CEO           BusinessTravel
CFO           MedicalTravel
CFO           BusinessTravel
HRLeader  MedicalTravel

Table2: MatchList (IEnumerable<MatchListRow>)
Authority
=============
MedicalTravel
BusinessTravel

How can I produce a list of Positions who have all the Authorities listed in MatchList?

In the example above, CFO and CEO should be produced, but not HR Leader.

I normally prefer the method-based syntax but I'm not too particular and would be just as pleased with query-based.

tk

0
Comment
Question by:tknudsen-qec
  • 7
9 Comments
 
LVL 21

Expert Comment

by:naspinski
ID: 36550139
Untested, but this should work:
var matches = MatchList.Select(x => x.Authority);//gets a IEnumerable<string>
var results = Authorities.Where(x => matches.Contains(x.CanAuthorize));

Open in new window

0
 
LVL 3

Author Comment

by:tknudsen-qec
ID: 36550335
That was pretty much identical to my first attempt naspinski, but it fails because "HR Leader" produces one match on "Medical" and therefore ends up in the results list with the others.  Tested as attached.

 
public class Authority
    {
      public Authority(string pos, string canauth)
      {
        Position = pos;
        CanAuthorize = canauth;
      }
      public string Position { get; set; }
      public string CanAuthorize { get; set; }
    }

    public class MatchList
    {
      public MatchList(string auth)
      {
        Authority = auth;
      }
      public string Authority { get; set; }
    }


	


    protected void Page_Load(object sender, EventArgs e)
    {
      List<Authority> Authorities = new List<Authority>();
      Authorities.Add(new Authority("CEO", "Medical"));
      Authorities.Add(new Authority("CEO", "Business"));
      Authorities.Add(new Authority("CFO", "Medical"));
      Authorities.Add(new Authority("CFO", "Business"));
      Authorities.Add(new Authority("HR Leader", "Medical"));

      List<MatchList> MatchLists = new List<MatchList>();
      MatchLists.Add(new MatchList("Medical"));
      MatchLists.Add(new MatchList("Business"));

      var matches = MatchLists.Select(x => x.Authority);//gets a IEnumerable<string>
      var results = Authorities.Where(x => matches.Contains(x.CanAuthorize));

    }

Open in new window


0
 
LVL 3

Author Comment

by:tknudsen-qec
ID: 36550352
This is how I'd do it in T-SQL but I'm unsure of the translation to LINQ:

SELECT DISTINCT A.Position
FROM #Authorities A
INNER JOIN
(
      SELECT Distinct Position, Authority
      FROM #Authorities A
      CROSS JOIN #MatchList M
) M ON M.Authority = A.CanAuthorize AND M.Position = A.Position
0
Master Your Team's Linux and Cloud Stack

Come see why top tech companies like Mailchimp and Media Temple use Linux Academy to build their employee training programs.

 
LVL 3

Author Comment

by:tknudsen-qec
ID: 36551034
Scratch that, my query doesn't work either.
0
 
LVL 3

Author Comment

by:tknudsen-qec
ID: 36551199
This seems to work but its not pretty.

 
// create a cartesian product of all possible position/authority combinations
      IEnumerable<Authority> product =
        from M in MatchLists
        from A in Authorities.Select( x => x.Position).Distinct()
        select new Authority(A, M.Authority);

      // get a list of positions that dont match back to our list of valid combinations
      IEnumerable<string> invalidpositions =
        from p in product
        join a in Authorities on new { p.CanAuthorize, p.Position } equals new { a.CanAuthorize, a.Position } into ps
        from a in ps.DefaultIfEmpty()
        where a == null
        select p.Position;

      // get a list of positions that arent in our list of non-matches
      IEnumerable<string> validpositions = (from a in Authorities
                                           where !invalidpositions.Any(x => x == a.Position)
                                           select a.Position).Distinct();

Open in new window


It emulates this SQL query:

   
SELECT DISTINCT Position
FROM #Authorities
WHERE Position NOT IN
(
	SELECT DISTINCT M.Position
	FROM
	(
		SELECT Distinct Position, Authority
		FROM #Authorities A
		CROSS JOIN #MatchList M
	) M
	LEFT OUTER JOIN #Authorities A ON M.Authority = A.CanAuthorize AND M.Position = A.Position
	WHERE A.Position IS NULL
)

Open in new window



Which, since it works and nobody has an alternative, will serve as the "answer".

Thx go to naspinski for making an effort however.

0
 
LVL 3

Author Comment

by:tknudsen-qec
ID: 36560149
I've requested that this question be closed as follows:

Accepted answer: 0 points for tknudsen-qec's comment http:/Q_27312340.html#36551199

for the following reason:

Own solution works, no working alternatives provided.<br /><br />I'd be pleased to re-offer points (if permitted) if a better solution provided.
0
 
LVL 3

Accepted Solution

by:
nixkuroi earned 500 total points
ID: 36558469
Try this one:

List<Authority> Authorities = new List<Authority>();
      Authorities.Add(new Authority("CEO", "Medical"));
      Authorities.Add(new Authority("CEO", "Business"));
      Authorities.Add(new Authority("CFO", "Medical"));
      Authorities.Add(new Authority("CFO", "Business"));
      Authorities.Add(new Authority("HR Leader", "Medical"));

      List<string> MatchLists = new List<string>();
      MatchLists.Add("Medical");
      MatchLists.Add("Business");


      List<string> authsWithAll = Authorities.GroupBy(i => i.Position, (key, group) => group.First()).ToDictionary(d => d.Position, d => d).Keys.ToList().ToDictionary(d => d, d => Authorities.Where(w => w.Position == d).ToList().ConvertAll(c => c.CanAuthorize).ToList()).Where(w => MatchLists.Except((List<string>)w.Value).ToList().Count == 0 && ((List<string>)w.Value).Except(MatchLists).ToList().Count == 0).ToDictionary(d=>d.Key, d=>d.Value).Keys.ToList();
0
 
LVL 3

Author Comment

by:tknudsen-qec
ID: 36560150
nixkuroi's solution works.  Please cancel the close-request so I can offer points.
0
 
LVL 3

Author Closing Comment

by:tknudsen-qec
ID: 36560168
@nixkuroi:
Thanks, that seems to work fine.  Thanks for not pointing out that I invented a "string" class for MatchLists.  Not sure what I was thinking.
0

Featured Post

The New “Normal” in Modern Enterprise Operations

DevOps for the modern enterprise offers many benefits — increased agility, productivity, and more, but digital transformation isn’t easy, especially if you’re not addressing the right issues. Register for the webinar to dive into the “new normal” for enterprise modern ops.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

International Data Corporation (IDC) prognosticates that before the current the year gets over disbursing on IT framework products to be sent in cloud environs will be $37.1B.
This article aims to explain the working of CircularLogArchiver. This tool was designed to solve the buildup of log file in cases where systems do not support circular logging or where circular logging is not enabled
In a recent question (https://www.experts-exchange.com/questions/29004105/Run-AutoHotkey-script-directly-from-Notepad.html) here at Experts Exchange, a member asked how to run an AutoHotkey script (.AHK) directly from Notepad++ (aka NPP). This video…

856 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question