LINQ Where query with object list - c#

I have a list of objects ListA with property Id and I have to make a query in a table that has a column Id and find the rows that the ids are the same. How exactly can I achieve that with a single query and not a foreach loop of listA?
Thank you for your time
foreach(var object in listA)
{
context.Table.Where(x => x.id == object.Id)....
}

Looks like you want to return all rows from the table that have an ID contained in the list of objects with the same ID. The following will achieve this. I can modify my answer to suit your need. Just let me know if you are looking for something slightly different.
void Main()
{
var listA = new List<A> { new A { Id = 1 }, new A { Id = 4 } };
var results = context.Table
.Where(t => listA.Select(l => l.Id).Contains(t.Id))
}
public class A
{
public int Id { get; set; }
}

Related

Advanced LINQ filtering

I have problem with advanced filtering data using LINQ.
I'd like to get list of Plan classes with Details list where Arguments in Items Lists contains specific characters. Also the Items list should contains only this filtered elements.
My classes look like below:
class Plan
{
public string Name { get; set; }
public List<Detail> Details { get; set; }
public Plan()
{
Details = new List<Detail>();
}
}
class Detail
{
public string Setting { get; set; }
public List<Item> Items { get; set; }
public Detail()
{
Items = new List<Item>();
}
}
class Item
{
public string Arguments { get; set; }
}
My current solution look like this, but I think it isn't the best option. I tried to write this code using Where and Any, but I've got Plans list where Items contains all items.
var filteredPlans = plans.Select(x =>
new Plan
{
Name = x.Name,
Details = x.Details.Select(y =>
new Detail
{
Setting = y.Setting,
Items = y.Items.Where(c => c.Arguments.Contains("...")).Select(z =>
new Item
{
Arguments = z.Arguments
}).ToList()
}).ToList()
});
How can I write this code using WHERE statement or What is the best solution to do that?
Also how can I get harvest difference using LINQ EXPECT based on Items List? e.g. plans: contains all plans with items, plans2: contains all plans with filtered items, and the plans3 should contains all plans with items which not belong to plans2.
Does this work for you?
First I limit to only the plans where any of their details contain any item that matches the filter.
Then I limit details for each plan to only those with any item that matches the filter
Then I limit items for each plan
private List<Plan> FilteredPlans(List<Plan> plans, string filter)
{
List<Plan> filteredPlans = plans.Where(plan => plan.Details.Any(detail => detail.Items.Any(item => item.Arguments.Contains(filter)))).ToList();
foreach (var plan in filteredPlans)
{
plan.Details = plan.Details.Where(detail => detail.Items.Any(item => item.Arguments.Contains(filter))).ToList();
foreach (var detail in plan.Details)
{
detail.Items = detail.Items.Where(item => item.Arguments.Contains(filter)).ToList();
}
}
return filteredPlans;
}
Also, here's another version as a single statement, but I think it's far less readable. I essentially limit the items first and then work my way backwards only keeping containers that aren't empty
private List<Plan> FilteredPlansWithSelect(List<Plan> plans, string filter)
{
List<Plan> filteredPlans = plans.Select(plan =>
new Plan()
{
Name = plan.Name,
Details = plan.Details.Select(detail =>
new Detail()
{
Setting = detail.Setting,
Items = detail.Items.Where(item => item.Arguments.Contains(filter)).ToList()
}).Where(detail => detail.Items.Count > 0).ToList()
}).Where(plan => plan.Details.Count > 0).ToList();
return filteredPlans;
}
Edited for grammer

Filtering from list of C# or LINQ

I am trying to filter from attachList the taxheaderID, it comes from my database which is structured as such.
public int attachmentID { get; set; }
public int headerID { get; set; }
public string uploadedfilename { get; set; }
public string originalfilename { get; set; }
public string foldername { get; set; }
Here is the code that gets data from the database:
public JsonResult GetAllAttach()
{
using (car_monitoringEntities contextObj = new car_monitoringEntities())
{
var attachList = contextObj.car_taxcomputationattachment.ToList();
return Json(attachList, JsonRequestBehavior.AllowGet);
}
}
These are my attempts:
attachList
.Select(x => x.headerID)
.Where(x => x == x)
.Take(1);
and:
attachList = attachList
.Where(al => attachList
.Any(alx => al.taxheaderID == alx.headerID
&& al.headerID == alx.headerID));
The problem is I want to parse multiple attach on a single headerID or filter them base on headerID. For example:
Problem to fix:
This is the table
Desired output:
Combined
data table:
data table
data table 2
Here is the actual solution that was made to get the output, but my coworker told me that it is not a good practice that's why I'm trying to filter it in the function itself. apologies for the trouble, thanks!
<div ng-repeat="att in attach|filter:{headerID:header.headerID}:true">
{{att.uploadedfilename}} <br />
</div>
To get attachments by Id
public JsonResult GetAllAttach(int headerId)
{
using (car_monitoringEntities contextObj = new car_monitoringEntities())
{
var attachList = contextObj.car_taxcomputationattachment
.Where(x => x.headerID == headerId)
.ToList();
return Json(attachList, JsonRequestBehavior.AllowGet);
}
}
If you want to have all data in one JSON result, then you need to create a nested view model.
Assuming you have the header id on which you want to filter in a local variable, you are almost correct
int headerIdToFind = 19;
// think of x as a local variable inside a foreach loop which
// iterates over each item in the attachList (it does not exist
// outside the where method)
// this is what you got wrong when you compared the item to itself
var filteredAttach = attachList.Where(x => x.headerId = headerIdToFind);
// if you want to select only some properties based on header id
// you can use select to project those properties
var filteredAttach = attachList.Where(x => x.headerId = headerIdToFind).
Select(x => new {x.attachmentId, x.folderName});
// based on last image, you only want to select (project) header id and the
// filename. so you do not need where (filter) at all
// you can put all the properties you need in the select clause
var filteredAttach = attachList.Select(x => new {x.headerId, x.attachmentId});
// you can enumerate the filtered attach list of convert it into a list
var filteredAttach = filteredAttach.ToList();

Foreach group items from a list of objects

I need to group a big list of elements according to a certain atribute.
Is it possible in C# to do a foreach with a 'where' clause in a list of objects or is there a better way?
For example, I have 5000 records and 3 groups that separate them.
Foreach list.item where item.group = group1{
do action one for every record from group1
}
and so on...
ps.: I already have the records at this point of code so I don't think Linq would help.
You can separate a larger list into smaller ones, based on a property, by using ToLookup. The ToLookup method will produce a dictionary of lists, where the key is the property value that you are separating them by and the list contains all of the elements that match.
For example, if your objects have a CategoryID you can separate them into a dictionary of lists like this:
var smallLists = bigList.ToLookup( item => item.CategoryID, item => item );
You can then iterate them like this:
foreach (var bucket in smallLists)
{
Console.WriteLine("Bucket:");
foreach (var item in bucket)
{
Console.WriteLine("Item {0} with category {1}", item.Name, item.CategoryID);
}
}
See a working example on DotNetFiddle.
I think that you want to do is to group items of list by a Group and then create another list with each group and his items.
If that is the case, you can do something like this:
var grouped = items/*.Where(c => c.group == //desired group if want's to filter//)*/
.GroupBy(c => c.group);
var results = grouped.Select(c => new {
Group = c.Key.group,
Items = c.Select(c => new { c.PropertyOfItem1, c.PropertyOfItem2, // etc // })
});
This basic template should do what you need. You can also use a dictionary to map the groups to.
using System.Linq;
class Program
{
class Item
{
public int Key { get; set; }
public string Name { get; set; }
}
static void Main(string[] args)
{
var actions = new Dictionary<int, Action<Item>> {
{ 1, Action1 },
{ 2, Action2 },
{ 3, Action3 }
};
var items = new List<Item>();
foreach (var group in items.GroupBy(x => x.Key))
{
var action = actions[group.Key];
foreach (var item in group)
{
action(item);
}
}
}
static void Action1(Item item)
{
}
static void Action2(Item item)
{
}
static void Action3(Item item)
{
}
}

How to get value from IEnumerable collection using its Key?

I have IEnumerable collection like following
IEnumerable<Customer> items = new Customer[]
{
new Customer { Name = "test1", Id = 999 },
new Customer { Name = "test2", Id = 989 }
};
I want to get value using key Id
I tried like following
public int GetValue(IEnumerable<T> items,string propertyName)
{
for (int i = 0; i < items.Count(); i++)
{
(typeof(T).GetType().GetProperty(propertyName).GetValue(typeof(T), null));
// I will pass propertyName as Id and want all Id propperty values
// from items collection one by one.
}
}
If you want to retrieve a Customer name from a collection by its Id:
public string GetCustomerName(IEnumerable<Customer> customers, int id)
{
return customers.First(c => c.Id == id).Name;
}
Using LINQ you can get all customers names (values) having specific value in this way:
var valuesList = items.Where(x => x.Something == myVar).Select(v => v.Name).ToList();
For single customer name you can do this:
var singleName = items.FirstOrDefault(x => x.Id == 1)?.Name;
Obviously, the Id can be 1, 2 or any other.
Edit:
I recommend you List<Customer> instead of Customer[]
So,
var items = new List<Customer>
{
new Customer { Name = "test1", Id = 999 },
new Customer { Name = "test2", Id = 989 }
};
// I will pass propertyName as Id and want all Id propperty values
// from items collection one by one.
If I understand you correctly
public static IEnumerable<object> GetValues<T>(IEnumerable<T> items, string propertyName)
{
Type type = typeof(T);
var prop = type.GetProperty(propertyName);
foreach (var item in items)
yield return prop.GetValue(item, null);
}
Just use LINQ to achieve what you want to do. if you want to retrieve a specific value you can use where like this:
public Customer GetCustomerById(IEnumerable<Customer> items,int key)
{
return items.Where(x=>x.id==key)
.Select(x =>x.Name)
.First();
}
this will retrieve the customer who match a specific Id.
Do you want to look things up repeatedly after creating the list? If so, you might want to consider creating a dictionary to do the lookups, like so:
IEnumerable<Customer> items = new Customer[]
{
new Customer {Name = "test1", Id = 999},
new Customer {Name = "test2", Id = 989}
};
var lookup = items.ToDictionary(itemKeySelector => itemKeySelector.Id);
var result = lookup[989];
Console.WriteLine(result.Name); // Prints "test2".
I'm assuming that you don't create the collection in the first place - if you had control over creating the original collection you could use a dictionary in the first place.
private TextBox [] Collectionstextboxonpanel(Panel panel)
{
var textBoxspanel1 = panel.Controls.OfType<TextBox>(); // select controls on panle1 by type
IEnumerable<TextBox> textBoxes = textBoxspanel1; // create collection if need
TextBox[] textBoxes1 = textBoxes.ToArray(); // Array collection
return textBoxes1; // get back TextBox Collection
}

How to group by records in c#

I am trying to use Group By method supported by LINQ.
I have this class
public class Attribute
{
public int Id {get;set;}
public string Name {get;set;}
public string Value {get;set;}
}
I have a service method that will retrive a IList
var attributes = _service.GetAll();
Id Name Value
7 Color Black
7 Color White
220 Size 16
Now I have another tow classes
one is
public class AttributeResourceModelSubItem
{
public string Name {get;set;}
public List<AttributeValueResourceModelSubItem> values { get; set; }
}
public class AttributeValueResourceModelSubItem
{
public int Id;
public string Name {get;set;}
}
I am trying to loop through the attributes list. and if the attribute id is the same, I wanna insert the records where id = to that id inside the AttributeValueResourceModelSubItem in which id = 1 and Name will be equal to the attribute value.
This what I got so far.
private IList<AttributeResourceModelSubItem> FormatAttributes(IList<Attribute> attributes)
{
Dictionary<int, Attribute> baseTypes = new Dictionary<int, Attribute>();
AttributeResourceModelSubItem attributeResourceModelSubItem = null;
var list = new IList<AttributeResourceModelSubItem>();
foreach (var item in attributes)
{
if (!baseTypes.ContainsKey(item.Id))
{
attributeResourceModelSubItem = new AttributeResourceModelSubItem()
attributeResourceModelSubItem.key = item.Name;
attributeResourceModelSubItem.values.Add(new AttributeValueResourceModelSubItem()
{
id = 1,
name = item.Value
});
list.Add(attributeResourceModelSubItem);
}
baseTypes.Add(item.Id, item);
}
return list;
}
Any help is appreciated.
It's pretty unclear from your example what you're actually trying to do, but this is the gist I get.
private IEnumerable<AttributeResourceModelSubItem> FormatAttributes(IEnumerable<Attribute> attributes)
{
return attributes.GroupBy(c => c.Id)
.Select(c => new AttributeResourceModelSubItem()
{
key = c.First().Name,
values = c.Select(x => new AttributeValueResourceModelSubItem()
{
id = 1,
name = x.value
}).ToList();
});
}
You should also definitely not use the word Attribute as a class name. That's already a .NET class.
I'll admit that I don't quite understand the id = 1 part, but I took that from your code. It also seems odd to group by the id then try and take the first name, but again that's what you have.
If you do, in fact, want to group by the name and take the id, which makes a little more sense, you'll want to swap a couple things around. Admittedly this structure still seems a little odd to me, but hopefully this will get you a couple steps closer to your goal.
private IEnumerable<AttributeResourceModelSubItem> FormatAttributes(IEnumerable<Attribute> attributes)
{
return attributes.GroupBy(c => c.name)
.Select(c => new AttributeResourceModelSubItem()
{
key = c.Key,
values = c.Select((item, index) => new AttributeValueResourceModelSubItem()
{
id = index + 1,
name = item.value
}).ToList();
});
}
I also made your id = 1 increment starting at one for each element in each values list. You might want that to be item.Id, or even just your original 1.

Categories

Resources