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]);
Related
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
I just need to make full outer join with Linq, But When i union two quires i get this error:
Instance argument: cannot convert from 'System.Linq.IQueryable' to 'System.Linq.ParallelQuery
And here is my full Code:
using (GoodDataBaseEntities con = new GoodDataBaseEntities())
{
var LeftOuterJoin = from MyCustomer in con.Customer
join MyAddress in con.Address
on MyCustomer.CustomerId equals MyAddress.CustomerID into gr
from g in gr.DefaultIfEmpty()
select new { MyCustomer.CustomerId, MyCustomer.Name, g.Address1 };
var RightOuterJoin = from MyAddress in con.Address
join MyCustomer in con.Customer
on MyAddress.CustomerID equals MyCustomer.CustomerId into gr
from g in gr.DefaultIfEmpty()
select new { MyAddress.Address1, g.Name };
var FullOuterJoin = LeftOuterJoin.Union(RightOuterJoin);
IEnumerable myList = FullOuterJoin.ToList();
GridView1.DataSource = myList;
GridView1.DataBind();
}
The types of your two sequences are not the same, so you can't do a Union.
new { MyCustomer.CustomerId, MyCustomer.Name, g.Address1 };
new { MyAddress.Address1, g.Name };
Try making sure that the fields have the same names and types in the same order.
Why not select it all as one thing? Depending on your setup (i.e., if you have foreign keys properly set up on your tables), you shouldn't need to do explicit joins:
var fullJoin = from MyCustomer in con.Customer
select new {
MyCustomer.CustomerId,
MyCustomer.Name,
MyCustomer.Address.Address1,
MyCustomer.Address.Name
};
Method syntax:
var fullJoin = con.Customers.Select(x => new
{
x.CustomerId,
x.Name,
x.Address.Address1,
x.Address.Name
});
union appends items from one collection to the end of another collection, so if each collection had 5 items, the new collection will have 10 items.
What you seem to want is to end up with 5 rows with more infomration is each. That's not a job for Union. You might be able to do it with Zip(), but you'll really be best with the single query as shown by DLeh.
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/
Going nuts over this.
Simple query but its just not working.
I simply need to get the company units that are not currently assigned to any users.
IDs are GUID type.
When debugging I see that there are 2 objects in companyUnits and 1 in userCompanyUnits.
I'm trying to get that 1 companyUnit ( that doesn't exist in userCompanyunit) to show.
Instead I get no results back.
Any idea what's wrong with the query? Maybe i can't compare based on guids ?
var companyUnitsList = from x in companyUnits
where !(from c in userCompanyUnits
select c.CompanyUnit.Id).Contains(x.Id)
select x;
Thanks in advance !
Here's a way of doing it without using the Except operator, and needing a custom IEqualityComparer:
List<Tuple<int, string>> allUnits = new List<Tuple<int, string>>();
allUnits.Add(new Tuple<int, string>(1, "unit1"));
allUnits.Add(new Tuple<int, string>(2, "unit2"));
allUnits.Add(new Tuple<int, string>(3, "unit3"));
List<Tuple<int, string>> assignedUnits = new List<Tuple<int, string>>();
assignedUnits.Add(new Tuple<int, string>(2, "unit2"));
var unassigned = allUnits.Where(m => !assignedUnits.Any(asgn => asgn.Item1 == m.Item1));
//Yields unit1 and unit3
Item1 corresponds to Unit.ID
Since you have it tagged as sql, I'm assuming this is queryable's and running against the database. Depending on the ORM and whether you have navigation properties defined and usable, you could do:
var notAssigned =
from x in companyUnits
where x.Users.Any() == false
select x;
IOW, whatever navigation property or collection exists to tie the company unit to the assigned user(s) is what you would use in the query (and would most likely translate to a sql 'exists')
var list1 = from s in new String[] {"ABC1","ABC2", "ABC3", "ABC4"} select new {Field1=s,Id = Guid.NewGuid().ToString()} ;
var list2 = new String[] {"ABC3","ABC4", "ABC5", "ABC6"} ;
var requiredList = (from i1 in list1
from i2 in list2
where !i1.Field1.Contains(i2)
select i1).Distinct();
I am having a terrible time finding a solution to what I am sure is a simple problem.
I started an app with data in Lists of objects. It's pertinent objects used to look like this (very simplified):
class A {
int[] Nums;
}
and
List<A> myListOfA;
I wanted to count occurrences of values in the member array over all the List.
I found this solution somehow:
var results
from a in myListOfA
from n in a.Nums
group n by n into g
orderby g.Key
select new{ number = g.Key, Occurences = g.Count}
int NumberOfValues = results.Count();
That worked well and I was able to generate the histogram I wanted from the query.
Now I have converted to using an SQL database. The table I am using now looks like this:
MyTable {
int Value1;
int Value2;
int Value3;
int Value4;
int Value5;
int Value6;
}
I have a DataContext that maps to the DB.
I cannot figure out how to translate the previous LINQ statement to work with this. I have tried this:
MyDataContext myContext;
var results =
from d in myContext.MyTable
from n in new{ d.Value1, d.Value2, d.Value3, d.Value4, d.Value5, d.Value6 }
group n by n into g
orderby g.Key
select new { number = g.Key, Occurences = g.Count() };
I have tried some variations on the constructed array like adding .AsQueryable() at the end - something I saw somewhere else. I have tried using group to create the array of values but nothing works. I am a relative newbie when it come to database languages. I just cannot find any clue anywhere on the web. Maybe I am not asking the right question. Any help is appreciated.
I received help on a microsoft site. The problem is mixing LINQ to SQL with LINQ to Objects.
This is how the query should be stated:
var results =
from d in MyContext.MyTable.AsEnumerable()
from n in new[]{d.Value1, d.Value2, d.Value3, d.Value4, d.Value5, d.Value6}
group n by n into g
orderby g.Key
select new {number = g.Key, Occureneces = g.Count()};
Works like a charm.
If you wish to use LINQ to SQL, you could try this "hack" that I recently discovered. It isn't the prettiest most cleanest code, but at least you won't have to revert to using LINQ to Objects.
var query =
from d in MyContext.MyTable
let v1 = MyContext.MyTable.Where(dd => dd.ID == d.ID).Select(dd => dd.Value1)
let v2 = MyContext.MyTable.Where(dd => dd.ID == d.ID).Select(dd => dd.Value2)
// ...
let v6 = MyContext.MyTable.Where(dd => dd.ID == d.ID).Select(dd => dd.Value6)
from n in v1.Concat(v2).Concat(v3).Concat(v4).Concat(v5).Concat(v6)
group 1 by n into g
orderby g.Key
select new
{
number = g.Key,
Occureneces = g.Count(),
};
How about creating your int array on the fly?
var results =
from d in myContext.MyTable
from n in new int[] { d.Value1, d.Value2, d.Value3, d.Value4, d.Value5, d.Value6 }
group n by n into g
orderby g.Key
select new { number = g.Key, Occurences = g.Count() };
In a relational database, such as SQL Server, collections are represented as tables. So you should actually have two tables - Samples and Values. The Keys table would represent a single "A" object, while the Values table would represent each element in A.Nums, with a foreign key pointing to the one of the records in the Samples table. LINQ to SQL
's O/R mapper will then create a "Values" property for each Sample object, which contains a queryable collection of the attached Values. You would then use the following query:
var results =
from sample in myContext.Samples
from value in sample.Values
group value by value into values
orderby values.Key
select new { Value = values.Key, Frequency = values.Count() };