I have a array of string say:
String[] Fields=new String[]{RowField,RowField1}
In which I can use the below query to get the values by specifying the values is query i.e RowField and RowField1:
var Result = (
from x in _dataTable.AsEnumerable()
select new
{
Name = x.Field<object>(RowField),
Name1 = x.Field<object>(RowField1)
})
.Distinct();
But if suppose I have many values in the Array like:
String[] Fields= new String[]
{
RowField,
RowField1,
RowField2,
.......
RowField1000
};
How can I use the query here without specifying each of the rowfield in the query?
How can i iterate through the array items inside the LINQ?
var Result = (
from x in _dataTable.AsEnumerable()
select (
from y in Fields
select new KeyValuePair<string, object>(y, x))
.ToDictionary())
.Distinct(DictionariesComparer);
You'll also need to write your own .ToDictionary() extension method and DictionariesComparer method (as Dictionary doesn't implement IEquatable).
Essentially, you want to retrieve specific fields from a DataTable without hardcoding the field names.
The following code will return a single dictionary object per row with the fields you specify in your array. There is no need to create additional extension methods or comparers:
var result = (from row in _dataTable.AsEnumerable()
let projection = from fieldName in fields
select new {Name = fieldName, Value = row[fieldName]}
select projection.ToDictionary(p=>p.Name,p=>p.Value));
The inner select picks the field values you need from each table row and stores them in the projection variable. The outer select converts this variable in a Dictionary
You can iterate over the result to get specific fields like this:
foreach (var row in result)
{
Console.WriteLine(row["field1"]);
}
EDIT:
The above code doesn't return distinct values. It is possible to return distinct values without writing a special comparer using group by but the code is not very pretty:
var result = (from row in table.AsEnumerable()
let projection = from fieldName in fields
select new { Name = fieldName, Value = row[fieldName] }
group projection by projection.Aggregate((v, p) =>
new {
Name = v.Name + p.Name,
Value = (object)String.Format("{0}{1}", v.Value, p.Value)
}) into g
select g.FirstOrDefault().ToDictionary(p=>p.Name,p=>p.Value));
The Aggregate creates a new projection whose Name and Value properties are the concatenation of all name and value fields. The result of the aggregate is used to group all rows and return the first row of each group. It works but it is definitely ugly.
It would be better to create a simple DictionaryComparer like the following code:
public class DictionaryComparer<TKey,TValue>: EqualityComparer<Dictionary<TKey,TValue>>
{
public override bool Equals(Dictionary<TKey, TValue> x, Dictionary<TKey, TValue> y)
{
//True if both sequences of KeyValuePair items are equal
var sequenceEqual = x.SequenceEqual(y);
return sequenceEqual;
}
public override int GetHashCode(Dictionary<TKey, TValue> obj)
{
//Quickly detect differences in size, defer to Equals for dictionaries
//with matching sizes
return obj.Count;
}
}
This allows you to write:
var result = (from row in table.AsEnumerable()
let projection = from fieldName in fields
select new {Name = fieldName, Value = row[fieldName]}
select projection.ToDictionary(p=>p.Name,p=>p.Value))
.Distinct(new DictionaryComparer<string, object>());
There is no foreach linq expression. I typically create my own extension method
Something along the lines of:
public static void Foreach<T>(this IEnumerable<T> items, Action<T> action)
{
foreach(T t in items)
{
action(t);
}
}
However beware if you're planning on using this with Linq2SQL as it could create a lot of db hits!
Related
I have a Table in my Entities with 370 columns ! Furthermore i have a string Array which is not known before runtime (comes from a website).
e.g.:
string [] columns = {"column1", "column2", "column3"}
How can i fire a linq to my entities which gives me only the result with the giving columns?
I searched for hours, but don`t suceed till now - any suggestions?
This is not something that you can do with Linq-to-Entities. You need to be able to declare the columns in your code.
A better approach would be to create the query in Sql using the column names in your array, and use something like Dapper to map the results to your objects.
You could instantiate an ExpandoObject in your Delegate and use Reflection to get the columns specified in the incoming array.
The following:
List<IDictionary<String, Object>> List = Context.Row_Type.Select(delegate(Row_Type Row) {
IDictionary<String, Object> Out = new ExpandoObject() as IDictionary<String, Object>;
PropertyInfo[] PIs = Row.GetType().GetProperties();
foreach(PropertyInfo PI in PIs) {
if(PI.GetIndexParameters().Length == 0) {
Out.Add(PI.Name, PI.GetValue(Row));
}
}
return Out;
}).ToList();
Will return a List < IDictionary< String, Object>> with all the properties, to return the desired columns just discriminate by PI.Name:
if(PI.Name == "Desired column"){ // Or Array index
// Add to Out:
Out.Add( PI.Name, PI.GetValue(Row) )
}
I'm guessing you don't really want to return a class with unknown column names. Would a dictionary of column names and values work for you? Your query would still have to retrieve all of the columns, but you can only return the ones you care about.
string [] columns = {"column1", "column2", "column3"}
var entity = GetEntity();
var dictionary = columns.ToDictionary(c => c, c => entity.GetType().GetProperty(c).GetValue(entity));
Or, if you have a collection...
var entities = GetEntities();
var results = entities
.Select(e => columns.ToDictionary(c => c, c => e.GetType().GetProperty(c).GetValue(e)));
I have a list (or can be array) of strings that I want to dynamically create an anonymous object from. How do I do this?
var dataSet = new DataSet();
dataSet.ReadXml(#"");
var dataTable = dataSet.Tables[0];
var dataRow = dataTable.Rows[0];
var keys = new List<string> {"Column1","Column2"};
var result = new {keys[0] = dataRow[keys[0]], keys[1] = dataRow[keys[1]]}
So that list named "keys" is going to be created outside this method and can contain 1 to many values. I tried creating a dictionary and looping through the list and adding key/value pairs to the dictionary but then I couldnt figure out how to convert the dictionary back to an anonymous type. I also experimented with the expando objects but that didn't seem to get me any farther.
I must be able to return an anonymous type as the result of this method will be using with the GroupBy clause of a LINQ query.
Here is the method I had to dynamically create the dictionary:
public object Key(DataRow dataRow, List<String> keys)
{
var dictionary = new IDictionary<string, object>;
foreach (string key in keys)
{
dictionary.Add(key, dataRow[key]);
}
return dictionary;
}
Here is my LINQ query:
var duplicates = dataTable.AsEnumerable().GroupBy(r => Key(r, keys)).Where(c => c.Count() > 1).ToList();
The GroupBy clause works if I hardcode in an anonymous type from the Key() method. Basically I just need the GroupBy clause to be dynamically set based upon the values in the keys list.
Stripping down your question, what you want is to be able to group a list of items based on a runtime property which could be composed of one or more properties of that item. In essence, it means you need a selector function (which is your Key method) that transforms an item into a key.
In order for GroupBy to work, it needs to be able to compare any two instances of the key to see if they're equal. This means the key needs to implement a meaningful Equals() method, or you need an IEqualityComparer implementation that does the work for you. In this case I wouldn't bother with creating a new Key, just write an Equality Comparer that can compare two DataRows directly:
var duplicates = dataTable
.AsEnumerable()
.GroupBy(r => r, new MyDataRowComparer(keys))
.Where(c => c.Count() > 1)
.ToList();
internal class MyDataRowComparer : IEqualityComparer<DataRow>
{
private readonly string[] _keys;
public MyDataRowComparer(string[] keys)
{
_keys = keys; // keep the keys to compare by.
}
public bool Equals(DataRow x, DataRow y)
{
// a simple implementation that checks if all the required fields
// match. This might need more work.
bool areEqual = true;
foreach (var key in _keys)
{
areEqual &= (x[key] == y[key]);
}
return areEqual;
}
public int GetHashCode(DataRow obj)
{
// Add implementation here to create an aggregate hashcode.
}
}
I have two lists I would like to compare them for updated/modified columns.
Compare 2 Lists of the same class and show the different values in a new list
I would like to do this using linq. The only problem is I am dealing with a lot of columns, over excess of 30 columns in each. Any suggestions would be of great help...
//In Dal
List<PartnerAndPartnerPositionEntity> GetAllPartnerAndPartnerPositionOldDB(int modelId);
List<PartnerAndPartnerPositionEntity> GetAllPartnerAndPartnerPosition(int modelId);
//BL
//get from new db
var list1= _partnerDAL.GetAllPartnerAndPartnerPosition(modelId);
//get from old db
var list2= _partnerDAL.GetAllPartnerAndPartnerPositionOldDB(modelId);
Let's assume that:
PartnerAndPartnerPositionEntity class contains a property named Id that represents the unique key of an item
Given the above you can:
Get all properties of your type
var properties = typeof(PartnerAndPartnerPositionEntity).GetProperties();
Join the two lists on the Id property and iterate through the properties to see which one has changed:
var list = list1.Join(list2,
x => x.Id,
y => y.Id,
(x, y) => Tuple.Create(x, y))
.ToList();
list.Foreach(tuple =>
{
foreach(var propertyInfo in properties)
{
var value1 = propertyInfo.GetValue(tuple.Item1, null);
var value2 = propertyInfo.GetValue(tuple.Item2, null);
if(value1 != value2)
Console.WriteLine("Item with id {0} has different values for property {1}.",
tuple.Item1,Id, propertyInfo.Name);
}
});
Well, if you want to avoid doing it the boring and tedious way, you need to use reflection to dynamically get the class members then get their values for each instance.
See C# Reflection - Get field values from a simple class for the code.
There...this will generate new IL!
public static class EqualityHelper
{
private ConcurrentDictionary<Type, object> _cache = new ConcurrentDictionary<Type, object>();
public bool AreEqual<T>(T left, T right)
{
var equality = (Func<T,T,bool>)_cache.GetOrAdd(typeof(T), CreateEquality<T>());
return equality(left, right);
}
private Func<T, T, bool> CreateEquality<T>()
{
var left = Expression.Parameter(typeof(T));
var right = Expression.Parameter(typeof(T));
var properties = from x in typeof(T).GetProperties()
where x.GetIndexParameters().Any() == false
select x;
var expressions = from p in properties
select Expression.Equal(
Expression.Property(left, p),
Expression.Property(right, p));
var body = expressions.Aggregate(Expression.AndAlso);
var lambda = Expression.Lambda<Func<T,T,bool>>(body, new [] {left, right});
return lambda.Compile();
}
}
With the following object hierarchy, I need to confirm whether or not all string Id values are present in Inventories of each SearchResult e.g.
Given a string[] list = { "123", "234", "345" } confirm all list values are present at least once in the array of Inventory elements. I'm curious if I can clean this up using one LINQ statement.
SearchResult
--
Inventory[] Inventories
Inventory
--
String Id
Right now, I'm splitting list e.g.
list.Split(').ToDictionary(i => i.ToString(), i => false)
And iterating the dictionary, testing each Inventory. Then, I create a new List<SearchResult> and add items if there are no false values left in the dictionary. This feels clunky.
Code
// instock: IEnumerable<SearchResult>
foreach (var result in instock)
{
Dictionary<string, bool> ids = list.Split(',').ToDictionary(i => i.ToString(), i => false);
foreach (var id in ids)
if (result.Inventory.Any(i => i.Id == id.Key))
ids[id.Key] = true;
if (!ids.Any(i => i.Value == false))
// instockFiltered: List<SearchResult>
instockFiltered.Add(result);
}
Here is a bit of code I wrote. The advantage here is that it uses a hash map, so it has theoretically linear complexity.
public static bool ContainsAll<T>(this IEnumerable<T> superset, IEnumerable<T> subset, IEqualityComparer<T> comparer)
{
var set = new HashSet<T>(superset, comparer);
return set.IsSupersetOf(subset);
}
This bit of LINQ will iterate over the entire stock and then interrogate the inventory (if it's not null) and find inventory that contain one of the values in your list.
var matches = instock.Where(stock => stock.Inventory != null && stock.Inventory.All(i => list.Contains(i.Id));
I have a field object and I create a list of fields:
class Field {
string objectName;
string objectType;
string fieldName;
string fieldValue;
//constructor...
}
List<Field> fieldList = new List<Field>();
Suppose I wanted to query this list to return a collection of distinct object names (to then be inserted into a checkedlistbox. How would I go about doing that?
I imagine some LINQ magic can manage this?
The expression should return a List of distinct object names from the list as defined. I converted it to a list since the docs for the CheckedListBox DataSource property indicated that it needs to implement IList or IListSource, not merely IEnumerable.
((ListControl)cbListBox).DataSource = fieldList.Select( f => f.objectName )
.Distinct()
.ToList() );
If accessing the checkedListBox as a ListControl doesn't give access to the DataSource (sometimes the docs lie), you could try:
cbListBox.Items.AddRange( fieldList.Select( f => f.objectName )
.Distinct()
.ToArray() );
Either of these work
Using var
1) var fieldNameCollection = from f in fieldList select f.FieldName;
2) Lambda syntax
var fieldNameCollection = fieldList.Select(f => f.FieldName);
Alternately, instead of using var, you can also use
IEnumerable fieldNameCollection = fieldList.Select(f => f.FieldName);
var q = from Field f in fileldList select f.objectName;
chkBoxList.DataSource = q.Distinct();