Linq JOIN, COUNT, TUPLE in C# - c#

I have table with columns: A, B and other columns(not important for this)
for example
A B C D
Peter apple
Thomas apple
Thomas banana
Lucy null
How can I get list of tuples {A, count of B} using join?
For my table it is: {Peter, 1}, {Thomas, 2}, {Lucy, 0}
Thanks

You've to just group by records on column A and count where B is not null
var result = (from t1 in cartItems
group t1 by t1.A into t2
select new
{
t2.Key,
count = t2.Count(p=> p.B != null)
}).ToList();

Since you mentioned table, I assume it is DataTable.
You could use simple Linq statements for what you need. Query returns List<Tuple> and Tuple contains two fields Item1 representing Name and Item2 representing Count
var results = dt.AsEnumerable()
.GroupBy(row=>row.Field<string>("A"))
.Select(s=> new Tuple<string, int>(s.Key, s.Count(c=>c!=null)))
.ToList();
Check this Demo

Related

Linq to query results of list of objects based on another list

I have a list of numbers as shown below:
1) List<long> list1 : 101, 102, 103
And I have a list of Objects, in which one property is long:
2) List<SomeObject> list2:
SomeObject[0]- (long)Id : 101,
Name: Adam,
Address:xxx
SomeObject[1]- (long)Id : 102,
Name: Bran,
Address:xxx
SomeObject[2]- (long)Id : 109,
Name: Queen,
Address:yyy
I want to query the second list if it has Id's present in list1. Meaning I should get list containing :
SomeObject[0]
SomeObject[1]
Tried the code below with no success:
(from t2 in list2
where list1 .Any(t => t2.Id.Contains(t)) == true
select t2);
Thanks in advance.
You can use Enumerable.Contains:
var query = from t2 in list2
where list1.Contains(t2.Id)
select t2;
if the values in list1 are uniqe you can also use the more efficient Join:
var query = from t2 in list2
join t1 in list1
on t2.Id equals t1
select t2;
Your approach doesn't work:
where list1.Any(t => t2.Id.Contains(t)) == true
because t2.Id returns a long which has no Contains method.
If you wanted to use Any you could use this:
where list1.Any(t => t2.Id == t)
The issue with your query is that you are trying to call Contains on a long. Instead it should have been list1 .Any(t => t2.Id == t). But instead you can just do a join.
from t1 in list1
join t2 in list2 on t1 equals t2.Id
select t2
You can also use the below code snippet to get the desired result, where
var result = list2.Where(l2 => list1.Any(l1 => l1 == l2.Id));

How to compare two lists with multiple objects and set values?

I have two lists. Each list has a Name object and and a Value object. I want to loop through list1 and check if each list1 Name object is the same as the list2 Name object (the linq code below does this).
If they match, then I want the List1 Value to be set with the list2 Value How can this be done?
list1 list2
Name Value Name Value
john apple John orange
peter null Peter grape
I need it to look like this:
list1 list2
Name Value Name Value
john orange john orange
peter grape peter grape
Linq code:
var x = list1.Where(n => list2.Select(n1 => n1.Name).Contains(n.Name));
For filtering you can use LINQ, to set the values use a loop:
var commonItems = from x in list1
join y in list2
on x.Name equals y.Name
select new { Item = x, NewValue = y.Value };
foreach(var x in commonItems)
{
x.Item.Value = x.NewValue;
}
In one result, you can get the objects joined together:
var output= from l1 in list1
join l2 in list2
on l1.Name equals l2.Name
select new { List1 = l1, List2 = l2};
And then manipulate the objects on the returned results. by looping through each and setting:
foreach (var result in output)
result.List1.Value = result.List2.Value;
You are looking for a left join
var x = from l1 in list1
join l2 in list2 on l1.Name equals l2.Name into l3
from l2 in l3.DefaultIfEmpty()
select new { Name = l1.Name, Value = (l2 == null ? l1.Value : l2.Value) };

Join two tables using linq, and fill a Dictionary of them

I've been searching how to join two tables (Data and DataValues, one to many) and fill a dictionary of type .
The records of Data(s) might be thousands (e.g. 500,000 or more) and each Data may have 10 to 20 DataValues which makes it a much heavier query, so the performance is really important here.
here is the code I've write:
// Passed via the arguments, for example, sensorIDs would contain:
int[] sensorIDs = { 0, 1, 2, 3, 4, 5, 6, 17, 18 };
Dictionary<Data, List<DataValue>> dict = new Dictionary<Data, List<DataValue>>();
foreach (Data Data in dt.Datas)
{
var dValues = from d in dt.Datas
join dV in dt.DataValues on d.DataID equals dV.DataID
where (SensorIDs.Contains(dV.SensorID))
select dV;
dict.Add(Data, dValues.ToList<DataValue>());
}
But this approach has a significant performance issue and takes a long time to execute.
Not sure if I need to use SQL Views. any suggestions?
You're querying way too many times. You can do this in one query.
var dict = (from d in dt.Datas
join dV in dt.DataValues on d.DataID equals dv.DataID
where SensorIDs.Contains(dv.SensorID)
select new { d, dV }).ToDictionary(o => o.d, o => o.dV.ToList());
In your foreach loop, you are fetching all Data and for each of them, you are doing the same thing.
Edit: Now that wasn't very clear, but I think you want to join only the DataValues that are in the SensorIDs array. In this case:
var dict = (from d in dt.Datas
let dV = (from dataValue in dt.DataValues
where SensorIDs.Contains(dataValue.SensorID) &&
dataValue.DataID = d.DataID
select dataValue)
select new { d, dV }).ToDictionary(o => o.d, o => o.dV.ToList());
You do not need a foreach loop in this case, you can use group join to create the dictionary straight from linq which should give you better performance.
dict=(from DataValue d in dt.DataValues
where sensorIDs.Contains(d.SensorID)
group d by d.DataID
into datavalues
join data in dt.Datas
on datavalues.Key equals data.DataId
select new {
Key = data,
Value = datavalues
}).ToDictionary(a=>a.Key,a=>a.Value.ToList());
or you can use linq expression methods
dict = dt.DataValues.Where(d=>sensorIDs.Contains(d.SensorID))
.GroupBy(a=>a.DataID)
.Join(dt.Datas,a=>a.Key,a=>a.DataId,
(a,b)=>new{Key=b,Value=a.ToList()})
.ToDictionary(a=>a.Key,a=>a.Value);
You don't need foreach loop. Try something like this in general:
var columns = dt.Columns.Cast<DataColumn>();
dt.AsEnumerable().Select(dataRow => columns.Select(column =>
new { Column = column.ColumnName, Value = dataRow[column] })
.ToDictionary(data => data.Column, data => data.Value));
Also, consider reading this: http://blogs.teamb.com/craigstuntz/2010/01/13/38525/

Join two dictionaries using a common key

I am trying to join two Dictionary collections together based on a common lookup value.
var idList = new Dictionary<int, int>();
idList.Add(1, 1);
idList.Add(3, 3);
idList.Add(5, 5);
var lookupList = new Dictionary<int, int>();
lookupList.Add(1, 1000);
lookupList.Add(2, 1001);
lookupList.Add(3, 1002);
lookupList.Add(4, 1003);
lookupList.Add(5, 1004);
lookupList.Add(6, 1005);
lookupList.Add(7, 1006);
// Something like this:
var q = from id in idList.Keys
join entry in lookupList on entry.Key equals id
select entry.Value;
The Linq statement above is only an example and does not compile. For each entry in the idList, pull the value from the lookupList based on matching Keys.
The result should be a list of Values from lookupList (1000, 1002, 1004).
What’s the easiest way to do this using Linq?
from id in idList.Keys
where lookupList.ContainsKey(id)
let value1 = idList[id]
let value2 = lookupList[id]
select new {id, value1, value2}
Or, more classically
from kvp1 in idList
join kvp2 in lookupList on kvp1.Key equals kvp2.Key
select new {key = kvp1.Key, value1 = kvp1.Value, value2 = kvp2.Value}
The mistake in your query is one of scoping:
from a in theAs
join b in theBs on (leftside) equals (rightside)
a is in scope in the leftside area. b is in scope in the rightside area.
I apologize if I misinterpretted your question, but do you just want to retrieve the Values from list B only where list A has a KeyValuePair with the same Key?
from lookup in lookupList
where idList.Keys.Contains(lookup.Key)
select lookup.Value;
var q = from id in idList
join entry in lookupList
on id.Key equals entry.Key
select entry.Value;
Your desired linq statement will look like that, ID and Entry needed to be switched around on the condition.
What do you think of this ?
var values = idList.Keys.Select(i => lookupList[i]);

joining in Linq

When i declare
int[] a = { 1, 2 ,10,30};
int[] b = { 10, 20, 30 };
var q = from item1 in a
join item2 in b
on item1 equals item2
into g
select g
1)What is actually getting selected into g ? It is difficult to understand the into keyword. if you give example to explain the keyword "into",i will be pleased.
2)
How do the following code actually projected ?
1 from a in db.coll1
2 join b in db.coll2 on a.PK equals b.PK into b_join
3 from b in b_join.DefaultIfEmpty()
4 where
5 b.PK == null
6 select new {
7 a.PK,
8 a.Value,
9 Column1 = (System.Int32?)b.PK,
10 Column2 = b.Value
}
in line 2 we are using "b' to select the item
in line 3 also we are using the same b ,does it mean we are overriding the data we selected
at line 2 ?
1) You are doing a group join. g will be an IGrouping for each element in a. g.Key will be the element from a, and g (which implements IEnumerable) will contain all of the matching elements from b. To understand this fully, try it out in LINQPad. Also, read the documentation.
2) The into keyword merges the first b into b_join, which will be an IGrouping as I described above. After that, the first b is no longer in scope.
If you use .NET Reflector on your compiled code, you can see that your first query is equivalent to the following:
IEnumerable<IEnumerable<int>> q = a.GroupJoin(b,
item1 => item1,
item2 => item2,
(item1, group) => group);
Note that you are performing a group join, but only returning the groups. Compare this with an ordinary join:
IEnumerable<int> q = a.Join(b,
item1 => item1,
item2 => item2,
(item1, item2) => item2);
This returns the elements in b that matches to each a, if any such element exists.

Categories