Remove items from list that exist in another list - c#

Both the following lists contain a QuoteID field. What is the best way to eliminate items from the currentQuotes list that have a QuoteID that exists in the quoteData list? Thanks.
//Establish - Instantiate lists
IList<QuotePaneView> currentQuotes = new List<QuotePaneView>();
IList<Quote> quoteData = new List<Quote>();
//Fill lists
currentQuotes = theQuotePaneService.GetAllQuotePanelStuff();
quoteData = theQuoteDataService.GetAllQuoteData();

A simple piece of Linq can help here:
Consider the following:
var list1 = new List<int>();
list1.Add(1);
list1.Add(3);
list1.Add(5);
var list2 = new List<int>();
list2.Add(1);
list2.Add(2);
list2.Add(3);
var diff = list1.Except(list2);

You can use Except to get the set difference based on the ID. Then you only have to join the result(the unique ID's that are not in quoteData) to the currentQuotes list.
var notInQuoteData = currentQuotes.Select(q => q.QuoteID).Except(quoteData.Select(q => q.QuoteID));
var result = (from qUnique in notInQuoteData
join q in currentQuotes on qUnique equals q.QuoteID
select q).ToList();

Related

How do I put distinct values from a LINQ query into a list?

I've looked at several answers to similar questions, but none of them solve my problem. All I need to do is get distinct values from a LINQ query (that queries a XML file) and put them into a list. Here is what I have tried:
var XmlData = XDocument.Load("PathToFile");
List<string> XmlItems = new List<string>();
var XQuery = from m in XmlData.Root.Elements()
where m.Attribute("Category").Value.ToString().Equals("TheCategory")
select (m.Attribute("TheAttribute").Value).Distinct().ToString();
XmlItems.AddRange(XQuery);
foreach (var item in XmlItems)
{
ComboBoxTeams.Items.Add(item);
}
The Distinct() function call is not giving the expected result. I'm unfamiliar with how to get distinct values from a LINQ query. Any suggestions?
At this point, your Distinct
var XQuery = from m in XmlData.Root.Elements()
where m.Attribute("Category").Value.ToString().Equals("TheCategory")
select (m.Attribute("TheAttribute").Value).Distinct().ToString();
is only for (m.Attribute("TheAttribute").Value), not for the whole statement
You may need to change it to
var XQuery = from m in XmlData.Root.Elements()
where m.Attribute("Category").Value.ToString().Equals("TheCategory")
select (m.Attribute("TheAttribute").Value.ToString()); //get everything first, ToString probably needed
var XQueryDistinct = XQuery.Distinct(); //get distinct among everything you got
You have the .ToString() and .Distinct() in the wrong places.
var XmlData = XDocument.Load("PathToFile");
List<string> XmlItems = new List<string>();
var XQuery = from m in XmlData.Root.Elements()
where m.Attribute("Category").Value.ToString().Equals("TheCategory")
select (m.Attribute("TheAttribute").Value).Distinct().ToString();
XmlItems.AddRange(XQuery);
foreach (var item in XmlItems)
{
ComboBoxTeams.Items.Add(item);
}
becomes:
var XmlData = XDocument.Load("PathToFile");
var XmlItems = (from m in XmlData.Root.Elements()
where m.Attribute("Category").Value.ToString().Equals("TheCategory")
select (m.Attribute("TheAttribute").Value.ToString())).Distinct();
foreach (var item in XmlItems)
{
ComboBoxTeams.Items.Add(item);
}
If you have a list of simple values, you need to remove the use of Distinct in your select and put after.
var XQuery = (from m in XmlData.Root.Elements()
where m.Attribute("Category").Value.ToString().Equals("TheCategory")
select (m.Attribute("TheAttribute").Value.ToString())).Distinct();
If you have complex objects you have two alternatives:
Using morelinq you can use DistinctBy:
XmlItems.DistinctBy(x => x.WhateverProperty);
Otherwise, you can use a group:
XmlItems.GroupBy(x => x.idOrWhateverOtherProperty)
.Select(g => g.First());
You might try
var uniqueList = yourList.Distinct().ToList();
after you got your non-unique list.

Linq query - returning a sum

I am having trouble figuring out how to do something like the following. This is purely pseudocode:
decimal totalActiveCost = (from i in _context.KeyActives
where i.Pk in (active1fk, active2fk, active3fk, active4fk, active5fk, keyActiveFk)
select sum(i.Cost)...`
Then summing the i.Cost. So basically, I need to return the i.Cost for each "Active" - so, for example, say active1fk is 1, active2fk is 2, and so on. I need to get the Cost for each of these and sum them up.
You can have your active foreign keys in a List<T> like:
List<int> activeFks = new List<int> {1,2,3,4,5,};
var sum = (from i in _context.KeyActives
where activeFks.Contains(i.PK)
select i.Cost).Sum();
Or with a method syntax:
var sum = _context.KeyActives
.Where(r=> activeFks.Contains(r.PK))
.Sum(r=> r.Cost);
Something like this will work:
List<Int> ids = new List<int>();
ids.Add(1);
ids.Add(2);
var result = _context.KeyActives.
Where(c => ids.Contains(c.id))
.Sum(c => c.Cost);
var ids = new List<int> {active1fk, active2fk, active3fk, active4fk, active5fk, keyActiveFk};
var sum = (from i in _context.KeyActives
where ids.Contains(i.Pk)
select i).Sum(a=> a.Cost);

Why I'm still getting System.NotSupportedException

My code is:
using( var ctxA = new AEntities())
using( var ctxB = new BEntities())
{
var listOfA = (from A in AEntities.AEntity select A).ToList();
var listOfB = (from B in BEntities.BEntity
where listOfA.Select( A = A.Id)contains(B.Id)
select B).ToList();
}
I'm getting the error:
The specified LINQ expression contains references to queries that are associated with different contexts.
However, because of 'ToList' I already did a fetch in AEntity thats makes second query only about one of the contexts, did not?
How can a separate the two queries still using one list to query the other?
Try to store just IDs into listOfA
var listOfA = (from A in AEntities.AEntity select A.Id).ToList();
var listOfB = (from B in BEntities.BEntity
where listOfA.Contains(B.Id)
select B).ToList();
If anyone wants to know, the answer to my question was:
var listOfA = (from A in AEntities.AEntity select A.Id).ToList();
List<long> listOfIdsOfA = listOfA.Select( A=>A.id).ToList();
var listOfB = (from B in BEntities.BEntity
where listOfIdsOfA.Contains(B.Id)
select B).ToList();
The only difference to Selman's answer was the creation of Id's list after the first query. That's why I need the whole entity too.

What is the LINQ query to get a Cartesian Product even when one set is EMPTY?

Imagine I have 2 list and one is empty:
List<string> foo = new List<string>(){ "Ali","wall-e","Ellie" };
List<string> bar = new List<string>();
And I obtain the Cartesian Product of 2:
var q = from f in foo
from b in bar
select new {f,b};
As bar is empty LINQ returns an empty result set.
Question:
How can I write the above query so that I can receive this result set:
Ali,NULL
Wall-e,NULL
Ellie,NULL
Maybe this is what you want:
var q = from f in foo.DefaultIfEmpty()
from b in bar.DefaultIfEmpty()
select new {f,b};

Get records which do not start with an alphabetical character in linq

I need to get a list of records that do not start with an alphabetical character, i.e. which either starts with a numerical character or any special character.
Whats the simple LINQ query to get this list?
List<string> Entries = new List<string>();
Entries.Add("foo");
Entries.Add("bar");
Entries.Add("#foo");
Entries.Add("1bar");
var NonAlphas = (from n in Entries
where !char.IsLetter(n.ToCharArray().First())
select n);
For Linq-to-sql you could hydrate your retrieval from the database by by enumerating the query (call ToList). From that point on, your operations will be against in-memory objects and those operations will not be translated into SQL.
List<string> Entries = dbContext.Entry.Where(n => n.EntryName).ToList();
var NonAlphas = Entries.Where(n => !char.IsLetter(n.First()));
Something like this?
List<string> lst = new List<string>();
lst.Add("first");
lst.Add("second");
lst.Add("third");
lst.Add("2abc");
var result = from i in lst where !char.IsLetter(i[0]) select i;
List<string> output = result.ToList();
Edit: I realized that using Regex here was overkill and my solution wasn't perfect anyway.
string[] x = new string[3];
x[0] = "avb";
x[1] = "31df";
x[2] = "%dfg";
var linq = from s in x where !char.IsLetter(s.ToString().First()) select s;
List<string> simplelist = new List<string>(linq);
/* in simple list you have only "31df" & "dfg" */
One thing to note is that you don't need to convert the string to a chararray to use linq on it.
The more consise version would be:
var list = new List<string> {"first","third","second","2abc"};
var result = list.Where(word => !char.IsLetter(word.First()));

Categories