Items is a List<Item> of Items, one of the properties of which is ID.
public static Item ItemByID(int id)
{
foreach (Item item in Items)
{
if (item.ID == id)
{
return item;
}
}
return null;
}
And:
public static Item ItemByID(int id)
{
return Items.FirstOrDefault(item => item.ID == id);
}
I think it is but I am not sure FirstOrDefault() will return null if it doesn't find it.
Yes, the two blocks of code function the same way.
Related
Consider removing duplicated elements of List from a specific class like below:
private List<MyClass> RemoveDuplicatedMyClass(List<MyClass> myObjects)
{
List<MyClass> uniqueMyClasses = new List<MyClass>();
foreach (MyClass item in myObjects)
{
if (uniqueMyClasses.FindAll(itm => itm.myAttribute == item.myAttribute).Count == 0)
{
uniqueMyClasses.Add(item);
}
}
return uniqueMyClasses;
}
I want to refactor RemoveDuplicatedMyClass to a generic version RemoveDuplicatedItems like below:
public static List<T> RemoveDuplicatedItems<T>(List<T> items, Predicate<T> match)
{
if (items == null)
{
return new List<T>();
}
List<T> uniqueItems = new List<T>();
foreach (T item in items)
{
// Check if item exists (= already added)! If not add to unique list.
if (uniqueItems.FindAll(match).Count < 1)
{
uniqueItems.Add(item);
}
}
return uniqueItems;
}
Problem: How can I get access to Predicate<T> match with the inner T item?
As guys mentioned in comments, it's a good idea to use Enumerable.DistinctBy and one solution is to use dynamic objects:
static List<dynamic> RemoveDuplicatedItems(List<dynamic>? items)
{
if (items == null)
{
return new List<dynamic>();
}
return items.DistinctBy(x=>x.MyAttribute).ToList();
}
and another and I think better option is to use abstraction, if you have some common properties between your classes you can create interface and define type of T as inheritor of that interface:
static List<T> RemoveDuplicatedItems<T>(List<T>? items) where T:ISomeCommonInterface
{
if (items == null)
{
return new List<T>();
}
return items.DistinctBy(x=>x.MyAttribute).ToList();;
}
So, I am new to LINQ and trying to figure out how to filter items.
That’s my task
public async Task<PagedList<Item>> GetItems (ItemParams itemParams) {
var items = _context.Items.AsQueryable ();
if (itemParams.CategoryId > 0) {
var category = GetCategory (itemParams.CategoryId);
items = items.Where (i => FilterItems (i, category.Result));
}
return await PagedList<Item>.CreatAsync (items, itemParams.PageNumber, itemParams.PageSize);
}
and the function that decides which items to return is
static bool FilterItems (Item item, Category category) {
if (item.CategoryId == category.Id) {
return true;
}
if (category.Children.Count > 0) {
foreach (Category cat in category.Children) {
return FilterItems (item, cat);
}
}
return false;
}
the get category func
public async Task<Category> GetCategory (int? id) {
if (id == null) {
return null;
}
var categories = _context.Categories.Include (x => x.Children).AsEnumerable ().Where (c => c.Id == id);
categories = Traverse (categories);
var category = await Task.FromResult (categories.First (c => c.Id == id));
return category;
}
Your filter will not work as expected, as the foreach returns at the first loop. Also the name FilterItems is not intuitive.
static bool ContainsItem(Category category, Item item)
{
return
category.Id == item.CategoryId ||
category.Children.Any(c => ContainsItem(c, item);
}
Since C# performs a short-circuit evaluation of the || Operator, the second term will not be evaluated if the first matches. Note that this is not a dirty trick, but is part of the C# specification.
From the code, it seems FilterItems() returns true if item is in current category or any sub-categories?
If that's the case, I think your current code has a problem: the recursive call to FilterItems() returns result immediately for the first sub-category without checking other sub-categories
Here is the modified code:
public static bool InCategoryOrSubCategory(Item item, Category category)
{
return item.CategoryId == category.Id ||
category.Children.Any(subCategory => InCategoryOrSubCategory(item, subCategory));
}
I change the name to InCategoryOrSubCategory to make it clearer
Here's a curried version, to make the Where call slightly nicer (but the method itself is a bit more cryptic):
public static Func<Item, bool> InCategoryOrSubCategory(Category category)
{
return item =>
item.CategoryId == category.Id ||
category.Children.Any(subCategory => InCategoryOrSubCategory(subCategory)(item));
}
Usage:
items.Where(InCategoryOrSubCategory(category))
I know there are multiple other threads on this but I can't wrap my head around why it
public int[] practice_5(List<int> items)
{
if (items == null)
{
return null;
}
else
{
List<int> items_sorted = items.OrderBy(p => p).ToList();
return items_sorted;
}
}
So I have sorted the list of items correctly. I'm assuming but no matter what workaround I try, it won't return it because it can't convert type List<int> to int[]?
Do I have to convert the variable items_sorted before returning?
Try this
public int[] practice_5(List<int> items)
{
if (items == null)
{
return null;
}
else
{
return items.OrderBy(p => p).ToArray();
}
}
or if you want a full refactor, and assuming C# 6.0 or higher.
public int[] practice_5(List<int> items)
{
return items?.OrderBy(p => p).ToArray();
}
I have list with items and I check if an item exists in a List. If it exists, I try to find it.
I think that it has a little overhead, because I currently make two passes over the list. Is it possible to do in single pass?
Currently I have.
public partial class Item
{
public string text;
public int id;
}
....
static List<Item> data = new List<Item>();
static stub = new Item() { text = "NaN", id = -1 };
public static Item Get(int targetId)
{
if (data.Any(f => f.id == targetId) == false)
{
return stub;
}
return data.Find(f => f.id == targetId);
}
I want something like
...
public static Item Get(int targetId)
{
Item result;
result = data.Find(f => f.id == targetId);
if (result == null)
{
return stub;
}
return result;
}
You seem to be looking for FirstOrDefault():
Item _stub = new Item
{
text = "NaN",
id = -1
};
public Item FindByID(int id)
{
// Find the first item that has the provided id, or null if none exist.
var existingItem = data.FirstOrDefault(i => i.id == id);
// When not found, return the _stub
return existingItem ?? _stub;
}
You also may want to reconsider your naming conventions and whether you actually need these members to be static.
You can use List.FindIndex:
public static Item get(int i)
{
int index = data.FindIndex(item => item.id == i);
if (index == -1) return stub;
return data[index];
}
If it's actually an array you can use Array.FindIndex:
public static Item get(int i)
{
int index = Array.FindIndex(data, item => item.id == i);
if (index == -1) return stub;
return data[index];
}
So FirstOrDefault() is the way to go. You can also use SingleOrDefault() if there is only supposed to be one item in that list.
static stub = new Item() { text = "NaN", id = -1 };
public static Item get(int i)
{
Item result;
result = data.FirstOrDefault(f => f.id == i);
if (result == null)
{
return stub;
}
return result;
}
I use an extension method for exactly this purpose
public static T FirstOrSpecificDefault<T>(this IEnumerable<T> list,
Func<T, bool> predicate, T defaultValue)
{
return list.FirstOrDefault(predicate) ?? defaultValue;
}
usage in your case would be
Item result = list.FirstOrSpecificDefault(f => f.id == i, stub);
I think you can try this:
return data.Find(f => f.id == i) ?? stub;
So I have a function that I pass Func call back to. I would also like to add some sort of selection projection to be able to do the projection on the object, meaning I would only perform one database call. The function looks something like this:
public T Get<T>(string id, Func<T> getItemCallback) where T : class
{
item = getItemCallback();
if (item != null)
{
doSomeThing(item);
// Here I would like to call something else that is
// expecting a specific type. Is there way to pass in a
// dynamic selector?
doSomethingElse(item.Select(x => new CustomType { id = x.id, name = x.name }).ToList());
}
return item;
}
void doSomethingElse(List<CustomType> custom)
{
....
}
Leme show how I cam currently calling this perhaps that will help:
public List<MyDataSet> GetData(string keywords, string id)
{
return _myObject.Get(
id,
() => db.GetDataSet(keywords, id).ToList());
// Perhaps I could add another parameter here to
// handled the projection ????
}
Thanks to Reed I figured it out...would look like this:
public T Get<T>(string id, Func<T> getItemCallback, Func<T, List<CustomType>> selector) where T : class
{
item = getItemCallback();
if (item != null)
{
doSomething(item);
var custom = selector(item);
if (custom != null)
{
doSomethingElse(custom);
}
}
return item;
}
And The call looks like:
public List<MyDataSet> GetData(string keywords, string id)
{
return _myObject.Get(
id,
() => db.GetDataSet(keywords, id).ToList(),
x => x.Select(d => new CustomType { id = d.ReferenceId, name = d.Name })
.ToList());
}
You would need to also pass in a conversion function:
public T Get<T>(string id, Func<T> getItemCallback, Func<T, List<CustomType>> conversion) where T : class
{
item = getItemCallback();
if (item != null)
{
doSomeThing(item);
if (conversion != null)
doSomethingElse(conversion(item));
}
return item;
}