Best way to implement "ReOrderable Collection" and Persist it to database - c#

My domain object :
public class MyDomainObject
{
public Guid Id { get; set; }
public string Name { get; set; }
public int DisplayOrder { get; set; }
}
Assuming sample data :
var list = new List<MyDomainObject>()
{
new MyDomainObject {Name = "Element1", DisplayOrder = 0},
new MyDomainObject {Name = "Element2", DisplayOrder = 1},
new MyDomainObject {Name = "Element3", DisplayOrder = 2},
new MyDomainObject {Name = "Element4", DisplayOrder = 3},
};
Now i change the DisplayOrder of the "Element3" from 2 to 1. My list should looks like that :
Element1 (DisplayOrder = 0)
Element3 (DisplayOrder = 1)
Element2 (DisplayOrder = 2)
Element4 (DisplayOrder = 3)
Now i remove "Element3"
Element1 (DisplayOrder = 0)
Element2 (DisplayOrder = 1)
Element4 (DisplayOrder = 2)
So what's the best way to persist this mechanism to database ?
Basically i need a "ReOrderableCollection" which will be populated from database with an OrderBy "DisplayOrder" where Collection Index Match "DisplayOrder", and persist back items by assigning DisplayOrder from Collection Index.

I answered a previous/similar question about re-ordering here:
How to design table that can be re-sequenced?
This does a good job of resaving the Order with no gaps. Depending on the size the lists resaving the Order may be a perfectly viable option, for long lists Mark Byers' idea looks pretty good.

From your examples it seems that you always want the sequence to be without gaps, starting from zero. But this means that removing the first element will require updating the row in the database for every single item in your list. It's simple and it will work (and these are good things) but it's not always ideal. Since you asked for "the best way" without really specifying what you mean by that, allow me to suggest an alternative method:
What really matters with a DisplayOrder is not the actual values but their relative order. If you want to improve performance with the database, you could consider relaxing the requirement that there should be no gaps and then try to find the smallest number of changes to the DisplayOrders to ensure that the correct order is stored, even if gaps are present in the resulting sequence. If you do this then adding, removing or moving a single item will typically only require updating one row in the database, with the exception that occasionally other items will have to be moved to create a gap where an item must be inserted between two others that have consecutive DisplayOrders.
You can also minimize the number of times that a gap is not available by starting with DisplayOrder 100, 200, 300 and later allowing for example an insertion with DisplayOrder 150 in between (or perhaps use a real/float type instead of an integer).
Another advantage of this method is if you use a database data comparison tool to observe changes between the current version of the database and older versions it will be easier to see what modifications have been made to the display order. You will only see changes in the display order of items that have actually been moved by the user, rather than half the list change each time an item is removed. It will also reduce the size of backups if you use an incremental backup strategy.
I'd say though that these advantages are not significant advantages over the naive method for most cases. It depends on your system whether it is worth implementing this system or just keeping it simple. If in doubt, keep it simple. For systems with small lists, few modifications and where you don't care about the change history, overwriting the entire list with new DisplayOrders each time will probably be just fine.

For what I can see it seems that DisplayOrder has the same value of the index property of the collection. So I will try to use that instead of a DisplayOrder property. On the DB I will use the DisplayOrder column to read and save the items but not on the domain objects.
HTH
ema

Now I'm assuming that you do want to always reorganize your list so that the DisplayOrder starts at 0 and increases without gaps, and you want this to happen automatically. You could implement your own collection type and an interface IDisplayOrderable and have the members of your type that change the list also automaticaly update the DisplayOrder of the items in the collection. As opposed to my other answer which was about an alternative way to store the data in the datase, this answer shows how to write a client class that could make it easier to automatically synchronize the DisplayOrder in your objects with your list indexes so that when you are ready to submit the changes to the database, the DisplayOrder field is already set correctly for you.
I think the answer is best given as some source code:
using System;
using System.Collections.Generic;
using System.Linq;
interface IDisplayOrderable
{
int DisplayOrder { get; set; }
}
class ReorderableList<T> : IList<T> where T : IDisplayOrderable
{
List<T> list = new List<T>();
private void updateDisplayOrders()
{
int displayOrder = 0;
foreach (T t in list)
{
t.DisplayOrder = displayOrder++;
}
}
public ReorderableList() { }
public ReorderableList(IEnumerable<T> items)
{
list = new List<T>(items.OrderBy(item => item.DisplayOrder));
}
public void Insert(int index, T item)
{
list.Insert(index, item);
updateDisplayOrders();
}
public void Add(T item)
{
list.Add(item);
updateDisplayOrders();
}
public bool Remove(T item)
{
bool result = list.Remove(item);
if (result)
updateDisplayOrders();
return result;
}
public IEnumerator<T> GetEnumerator()
{
return list.GetEnumerator();
}
// TODO: Other members and methods required to implement IList<T>...
}
class Item : IDisplayOrderable
{
public string Name { get; set; }
public int DisplayOrder { get; set; }
}
class Program
{
static void Main()
{
Item foo = new Item { Name = "foo", DisplayOrder = 0 };
Item bar = new Item { Name = "bar", DisplayOrder = 1 };
Item baz = new Item { Name = "baz", DisplayOrder = 2 };
// Pretend this came from the database.
IEnumerable<Item> query = new Item[] { bar, foo };
// The constructor automatically reorder the elements.
ReorderableList<Item> items = new ReorderableList<Item>(query);
items.Add(baz);
items.Remove(foo);
items.Insert(1, foo);
foreach (Item item in items)
Console.WriteLine("{0} : {1}", item.Name, item.DisplayOrder);
}
}
Output:
bar : 0
foo : 1
baz : 2
Perhaps this was the sort of answer you were looking for?

I maybe founded a solution by creating a custom List which take an Lamba Expression in constructor parameter in order the list to be able to self update items property "DisplayOrder".
The sample class
public class MyItem
{
public string Name { get; set; }
public int DisplayOrder { get; set; }
}
The sample program
public class Program
{
static void Main(string[] args)
{
var list = new DisplayOrderableList<MyItem>(p => p.DisplayOrder)
{
new MyItem{ Name = "Item 1"},
new MyItem{ Name = "Item 2"},
new MyItem{ Name = "Item 3"},
};
var item = list.Where(p => p.Name == "Item 2").FirstOrDefault();
list.MoveUp(item);
list.ForEach(p => Console.WriteLine("{0}-{1}", p.Name, p.DisplayOrder));
Console.WriteLine();
list.MoveDown(item);
list.ForEach(p => Console.WriteLine("{0}-{1}", p.Name, p.DisplayOrder));
Console.WriteLine();
Console.ReadLine();
}
}
The custom implementation of DisplayOrderableList
public class DisplayOrderableList<T> : List<T>
{
#region Private Fields
private PropertyInfo _property;
#endregion
#region Constructors
public DisplayOrderableList(Expression<Func<T, int>> expression)
{
ValidateExpression(expression);
}
#endregion
#region Public Methods
public void MoveUp(T item)
{
if (!Contains(item))
throw new ArgumentNullException("item", "item doesn't exists in collection");
var idx = IndexOf(item);
RemoveAt(idx);
if (idx > 0)
Insert(idx - 1, item);
else
Insert(0, item);
UpdateDisplayOrder();
}
public void MoveDown(T item)
{
if (!Contains(item))
throw new ArgumentNullException("item", "item doesn't exists in collection");
var idx = IndexOf(item);
RemoveAt(idx);
if (idx + 1 > Count)
Add(item);
else
Insert(idx + 1, item);
UpdateDisplayOrder();
}
#endregion
#region Private Methods
private void UpdateDisplayOrder()
{
foreach (var item in this)
{
_property.SetValue(item, IndexOf(item), null);
}
}
#endregion
#region Expression Methods
private void ValidateExpression(Expression<Func<T, int>> expression)
{
var lamba = ToLambaExpression(expression);
var propInfo = ToPropertyInfo(lamba);
if (!propInfo.CanWrite)
{
throw new ArgumentException(String.Format("Property {0} as no setters", propInfo.Name));
}
_property = propInfo;
}
private static LambdaExpression ToLambaExpression(Expression expression)
{
var lambda = expression as LambdaExpression;
if (lambda == null)
{
throw new ArgumentException("Invalid Expression");
}
var convert = lambda.Body as UnaryExpression;
if (convert != null && convert.NodeType == ExpressionType.Convert)
{
lambda = Expression.Lambda(convert.Operand, lambda.Parameters.ToArray());
}
return lambda;
}
private static PropertyInfo ToPropertyInfo(LambdaExpression expression)
{
if (expression == null)
{
throw new ArgumentNullException("expression", "Expression cannot be null.");
}
var prop = expression.Body as MemberExpression;
if (prop == null)
{
throw new ArgumentException("Invalid expression");
}
var propInfo = prop.Member as PropertyInfo;
if (propInfo == null)
{
throw new ArgumentException("Invalid property");
}
return propInfo;
}
#endregion
}
This now get the following output :
Item 2-0
Item 1-1
Item 3-2
Item 1-0
Item 2-1
Item 3-2
It's a proof of concept and should be enhanced but it's a beggining.
What do you think about this ?

I know this is a old question, but the comments here and in another question helped me solve a similar issue and I wanted to provide my code in case it helps anyone else out looking for something similar. You can find my code at the following link:
How to design table that can be re-sequenced?

Related

How to set flag in one list for the Id's which match with the Id's in another list using Lambda expression c#

I have two lists classes
public class class1{
public Int Id { get; set; }
public Bool Flag{ get; set; }
}
public class class2{
public Int Id { get; set; }
}
Now i have List<class1> and List<class2>,
Now i have to update Flag property to true in List<class1> for only those Ids which match with the Id's present in List<class2> using lambda expression c#.Don't want to use foreach.
using lambda expression. Don't want to use foreach.
That's usually a silly requirement and a hallmark that you're not really familiar with C#, Linq or performance analysis. You have a collection whose elements you want to modify, so you should use foreach().
If you're trying out functional programming, then you should treat the list elements as immutable and project into a new collection.
The first part of your problem, looking up which list elements to modify based on a presence of one of their properties in another collection's elements' properties, is trivial:
var elementsToModify = list1.Where(l1 => list2.Any(l2 => l2.Id == l1.Id));
Now with a foreach(), this'll be simple:
foreach (var l1 in elementsToModify)
{
l1.Flag = true;
}
Or, even denser (not that less code equals more performance):
foreach (var l1 in list1.Where(l1 => list2.Any(l2 => l2.Id == l1.Id)))
{
l1.Flag = true;
}
So, there's your code. But you didn't want to use foreach(). Then you need to project into a new collection:
var newList1 = list1.Where(l1 => list2.Any(l2 => l2.Id == l1.Id))
.Select(l1 => new Class1
{
Id = l1.Id,
Flag = true,
})
.ToList();
There you have it, a List<Class1> with only flagged items. Optionally you could use this list in a foreach() to update the original list1. Oh, wait.
The below solution does not use the classical "for each", but is compiled to one under the hood. If that's not what you meant, then please explain what you are trying to achieve. Using for each in this example is a good approach. One could also use while or for loops, but is it really what's being asked here?
Object definition:
public class MyObject
{
public int Id { get; set; }
public bool Flag { get; set; }
}
List initialization:
var list = new List<MyObject>()
{
new MyObject() { Id= 1 },
new MyObject() { Id= 2 },
new MyObject() { Id= 3 },
new MyObject() { Id= 4 }
};
var list2 = new List<MyObject>()
{
new MyObject() { Id= 2 },
new MyObject() { Id= 4 }
};
Code:
list.ForEach(el => el.Flag = list2.Any(el2 => el2.Id == el.Id));
EDIT:
An example with a while loop (a bit nasty to do it this way):
int i = -1;
int numberOfElements = list.Count;
while (++i < numberOfElements)
{
list[i].Flag = list2.Any(el => el.Id == list[i].Id);
}
I guess you can write a for loop yourself...

Custom OrderBy in Linq with singly linked entity list

I'm trying to come up with an efficient solution to be able to query the entity list and order it correctly. I have created a singly linked list type structure in SQL DB schema. I am using GUID as my IDs but for simplicity, I'll use int here. I could solve this problem easily by having a SortOrder column on the DB but because of other requirements, this is how I have to implement this table.
I have a table structure that looks like the following entity model:
public class Record
{
public int ID;
public string Name;
public int? ChildID; //References the next record
}
My initial thought is to create a partial class like the following:
public partial class Record
{
public int SortOrder
{
get
{
//query table and loop through the entire list building it from
//the bottom and keeping count of the integer sort order and return
//the one specific to this record
}
}
}
However, this seems very inefficient to have to query the entire list every time and iterate through to find the SortOrder. Is there anything else I can leverage like a custom OrderBy function or anything? I'm trying sort by the order that would be created when iterating a building the list. For instance, the record with ChildID = null, is the last one in the list, since it does not have a child. I'll start with that record, then get the next one above it that references the previous as its ChildID and go until there is no more in the list that has a reference to ID, which should be when the list is complete and ordered correctly. No two records have the same ChildID.
If I had the following 3 records in a list,
ID = 3, Name = "Apple", ChildID = 6,
ID = 54, Name = "Orange", ChildID = 3,
ID = 6, Name = "Banana", ChildID = null
Then I would expect to get Orange, Apple, Banana, in that order.
One way to do it would be to write a method that will return a list in sorted order. You would first find the record with ChildId == null, add it to the results list, and then continue to search for items where item.ChildId == previousItem.Id, and then insert them at the beginning of the list:
private static IEnumerable<Record> OrderRecords(IReadOnlyCollection<Record> records)
{
// "Exit fast" checks
if (records == null) return null;
if (records.Count < 2) return records.ToList();
// Get last record and add it to our results
Record currentRecord = records.Single(r => r.ChildID == null);
var results = new List<Record> {currentRecord};
// Keep getting the parent reference to the previous record
// and insert it at the beginning of the results list
while ((currentRecord = records.SingleOrDefault(r =>
r.ChildID == currentRecord.ID)) != null)
{
results.Insert(0, currentRecord);
}
return results;
}
In use, this would look something like:
private static void Main()
{
var records = new List<Record>
{
new Record {ID = 3, Name = "Apple", ChildID = 6},
new Record {ID = 54, Name = "Orange", ChildID = 3},
new Record {ID = 6, Name = "Banana", ChildID = null}
};
var sortedRecords = OrderRecords(records);
Console.WriteLine(string.Join(", ", sortedRecords.Select(r => r.Name)));
Console.Write("\nPress any key to exit...");
Console.ReadKey();
}
Output
Given that the record ID order is random, and assuming that the List you are ordering is complete, or that you won't run out of memory/time if you have to scan the entire table to order the list, I think the best you can do is compute the depth for a Record and cache the results:
I am using the List as the table, but you could use the table instead if the list you want to order is incomplete:
public partial class Record {
static Dictionary<int, int> depth = new Dictionary<int, int>();
public int Depth(List<Record> dbTable) {
int ans = 0;
var working = new Queue<int>();
var cur = this;
do {
if (depth.TryGetValue(cur.ID, out var curDepth)) {
ans += curDepth;
break;
}
else {
working.Enqueue(cur.ID);
cur = dbTable.FirstOrDefault(r => r.ChildID == cur.ID);
if (cur != null)
++ans;
}
} while (cur != null);
var workAns = ans;
while (working.Count > 0) {
var workingID = working.Dequeue();
depth.Add(workingID, workAns);
--workAns;
}
return ans;
}
}
Update: I re-wrote the code to use a specific queue; my first version was recursive and that was straightforward but risked overflowing the stack and my second version didn't cache the intermediate results when following the linked list which wasn't very efficient. Using a queue of the intermediate IDs ensures I only follow a particular chain depth once.
Now that you have a Depth method, sorting is easy:
var ans = work.OrderBy(w => w.Depth(work));
The best algorithm for this task is to prepare a fast lookup data structure (like Dictionary) of Record by ChildID. Then the ordered result can be produced backwards starting with ChildID = null and using the record ID to find the previous record.
Since the hash lookup time complexity is O(1), the time complexity of the algorithm is linear O(N) - the fastest possible.
Here is the implementation:
static Record[] Ordered(IEnumerable<Record> records)
{
var recordByNextId = records.ToDictionary(e => e.ChildID.Wrap());
var result = new Record[recordByNextId.Count];
int? nextId = null;
for (int i = result.Length - 1; i >=0; i--)
nextId = (result[i] = recordByNextId[nextId]).ID;
return result;
}
The explanation of e.ChildID.Wrap() custom extension method. I wish I can use simply e.ChildID, but the BCL Dictionary class throws annoying exception for null key. To overcome that limitation in general, I use a simple wrapper struct and "fluent" helper:
public struct ValueWrapper<T> : IEquatable<ValueWrapper<T>>
{
public readonly T Value;
public ValueWrapper(T value) => Value = value;
public bool Equals(ValueWrapper<T> other) => EqualityComparer<T>.Default.Equals(Value, other.Value);
public override bool Equals(object obj) => obj is ValueWrapper<T> other && Equals(other);
public override int GetHashCode() => EqualityComparer<T>.Default.GetHashCode(Value);
public static implicit operator ValueWrapper<T>(T x) => new ValueWrapper<T>(x);
public static implicit operator T(ValueWrapper<T> x) => x.Value;
}
public static class ValueWrapper
{
public static ValueWrapper<T> Wrap<T>(this T value) => new ValueWrapper<T>(value);
}

Comparing two lists of class objects similar to a Diff Tool

Question moved here.
My requirement is to write a program that sort of mimics diff tools. Yes there are quite a few libraries and open source code that accomplishes this purpose, but I would like to write my own comparer.
Here's the starting point. I have a class called DataItem which looks like this:
public class DataItem
{
public DataItem() { }
public DataItem(string d, string v) { Data = d; Value = v; }
public string Data { get; set; }
public string Value { get; set; }
}
I have two lists of these class objects, let's call them PRE and POST and take some example values as follows. 'Data' part will be unique in a list.
preList: (Data,Value)
AAA,0
BBB,1
CCC,3
DDD,4
FFF,0
GGG,3
postList: (Data,Value)
AAA,0
BBB,2
DDD,4
EEE,9
FFF,3
Think of PRE as the original list, and POST as the list after some changes done. I would like to compare the two, and categorize them into three categories:
Added Items - An item with a new 'Data' added to the list.
Removed Items - An item was removed from the list.
Diff Items - 'Data' is found in both PRE and POST lists, but their corresponding 'Value' is different.
So when categorized they should look like this:
Added Items:
EEE,9
Removed Items:
CCC,3
GGG,3
Diff Items:
BBB
FFF
I have another DiffItem class, to objects of which I would like to put the final results. DiffItem looks like this:
public class DiffItem
{
public DiffItem() { }
public DiffItem(string data, string type, string pre, string post) { Data = data; DiffType = type; PreVal = pre; PostVal = post; }
public string Data { get; set; }
public string DiffType { get; set; } // DiffType = Add/Remove/Diff
public string PreVal { get; set; } // preList value corresponding to Data item
public string PostVal { get; set; } // postList value corresponding to Data item
}
To accomplish this, first I extended IEqualityComparer and wrote a couple of comparers:
public class DataItemComparer : IEqualityComparer<DataItem>
{
public bool Equals(DataItem x, DataItem y)
{
return (string.Equals(x.Data, y.Data) && string.Equals(x.Value, y.Value));
}
public int GetHashCode(DataItem obj)
{
return obj.Data.GetHashCode();
}
}
public class DataItemDataComparer : IEqualityComparer<DataItem>
{
public bool Equals(DataItem x, DataItem y)
{
return string.Equals(x.Data, y.Data);
}
public int GetHashCode(DataItem obj)
{
return obj.Data.GetHashCode();
}
}
Then used Except() and Intersect() methods as follows:
static void DoDiff()
{
diffList = new List<DiffItem>();
IEnumerable<DataItem> preOnly = preList.Except(postList, new DataItemComparer());
IEnumerable<DataItem> postOnly = postList.Except(preList, new DataItemComparer());
IEnumerable<DataItem> common = postList.Intersect(preList, new DataItemComparer());
IEnumerable<DataItem> added = postOnly.Except(preOnly, new DataItemDataComparer());
IEnumerable<DataItem> removed = preOnly.Except(postOnly, new DataItemDataComparer());
IEnumerable<DataItem> diffPre = preOnly.Intersect(postOnly, new DataItemDataComparer());
IEnumerable<DataItem> diffPost = postOnly.Intersect(preOnly, new DataItemDataComparer());
foreach (DataItem add in added)
{
diffList.Add(new DiffItem(add.Data, "Add", null, add.Value));
}
foreach (DataItem rem in removed)
{
diffList.Add(new DiffItem(rem.Data, "Remove", rem.Value, null));
}
foreach (DataItem pre in diffPre)
{
DataItem post = diffPost.First(x => x.Data == pre.Data);
diffList.Add(new DiffItem(pre.Data, "Diff", pre.Value, post.Value));
}
}
This does work and gets the job done. But I'm wondering if there's a 'better' way to do this. Note that I put quotes around the word 'better', because I don't have a proper definition for what would make this better. Perhaps is there a way to get this done without as many 'foreach' loops and use of Except() and Intersetc(), since I would imagine that behind the Linq there's quite a bit of iterations going on.
Simply put, is there a cleaner code that I can write for this? I'm asking mostly out of academic interest and to expand my knowledge.
I don't think you need your IEqualityComparer:
var added = from a in postList
where !preList.Any(b => b.Data == a.Data)
select new DiffItem(a.Data, "Add", null, a.Value);
var removed = from b in preList
where !postList.Any(a => a.Data == b.Data)
select new DiffItem(b.Data, "Remove", b.Value, null);
var diff = from b in preList
join a in postList on b.Data equals a.Data
where b.Value != a.Value
select new DiffItem(b.Data, "Diff", b.Data, a.Data);
var diffList = added.ToList();
diffList.AddRange(removed);
diffList.AddRange(diff);

Element Metrics with Custom collection in C#

I am trying to figure out the best way to organise a bunch of my data classes, given I need to be able to access some metrics on them all at some point.
Here's a snippet of my OR class:
public enum status { CLOSED, OPEN }
public class OR
{
public string reference { get; set; }
public string title { get; set; }
public status status { get; set; }
}
Not every OR I initialise will have values for all properties. I want to be able to 'collect' thousands of these together in such a way that I can easily obtain a count of how many OR objects had a value set. For example:
OR a = new OR() { reference = "a" }
OR b = new OR() { reference = "b", title = "test" }
OR c = new OR() { reference = "c", title = "test", status = status.CLOSED }
Now these are somehow collected in such a way I can do (pseudo):
int titleCount = ORCollection.titleCount;
titleCount = 2
I would also want to be able gather metrics for the enum type properties, for example retrieve a Dictionary from the collection that looks like:
Dictionary<string, int> statusCounts = { "CLOSED", 1 }
The reason for wanting access to these metrics is that I am building two collections of ORs and comparing them side-by-side for any differences (they should be identical). I want to be able to compare their metrics at this higher level first, then break-down where precisely they differ.
Thanks for any light that can be shed on how to accomplish this. :-)
... to 'collect' thousands of these
Thousands is not a huge number. Just use a List<OR> and you can get all your metrics with Linq queries.
For example:
List<OR> orList = ...;
int titleCount = orList
.Where(o => ! string.IsNullOrEmpty(o.title))
.Count();
Dictionary<status, int> statusCounts = orList
.GroupBy(o => o.status)
.ToDictionary(g => g.Key, g => g.Count());
The existing answers using Linq are absolutely great and really elegant, so the idea presented below is just for posterity.
Here is a (very rough) reflection-based program that will alow you to count the "valid" properties in any collection of objects.
The validators are defined by you in the Validators dictionary so that you can easily change what is a valid/invalid value for each property. You may find it useful as a concept if you end up with objects having tons of properties and don't want to have to write inline linq metrics on the actual collection itself for every single property.
You could weaponise this as a function and then run it against both collections, giving you a basis to report on the exact differences between both since it records the references to the individual objects in the final dictionary.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
namespace reftest1
{
public enum status { CLOSED, OPEN }
public class OR
{
public string reference { get; set; }
public string title { get; set; }
public status status { get; set; }
public int foo { get; set; }
}
//creates a dictionary by property of objects whereby that property is a valid value
class Program
{
//create dictionary containing what constitues an invalid value here
static Dictionary<string,Func<object,bool>> Validators = new Dictionary<string, Func<object,bool>>
{
{"reference",
(r)=> { if (r ==null) return false;
return !String.IsNullOrEmpty(r.ToString());}
},
{"title",
(t)=> { if (t ==null) return false;
return !String.IsNullOrEmpty(t.ToString());}
},
{"status", (s) =>
{
if (s == null) return false;
return !String.IsNullOrEmpty(s.ToString());
}},
{"foo",
(f) =>{if (f == null) return false;
return !(Convert.ToInt32(f.ToString()) == 0);}
}
};
static void Main(string[] args)
{
var collection = new List<OR>();
collection.Add(new OR() {reference = "a",foo=1,});
collection.Add(new OR(){reference = "b", title = "test"});
collection.Add(new OR(){reference = "c", title = "test", status = status.CLOSED});
Type T = typeof (OR);
var PropertyMetrics = new Dictionary<string, List<OR>>();
foreach (var pi in GetProperties(T))
{
PropertyMetrics.Add(pi.Name,new List<OR>());
foreach (var item in collection)
{
//execute validator if defined
if (Validators.ContainsKey(pi.Name))
{
//get actual property value and compare to valid value
var value = pi.GetValue(item, null);
//if the value is valid, record the object into the dictionary
if (Validators[pi.Name](value))
{
var lookup = PropertyMetrics[pi.Name];
lookup.Add(item);
}
}//end trygetvalue
}
}//end foreach pi
foreach (var metric in PropertyMetrics)
{
Console.WriteLine("Property '{0}' is set in {1} objects in collection",metric.Key,metric.Value.Count);
}
Console.ReadLine();
}
private static List<PropertyInfo> GetProperties(Type T)
{
return T.GetProperties(BindingFlags.Public | BindingFlags.Instance).ToList();
}
}
}
You can get the title count using this linq query:
int titleCount = ORCollection
.Where(x => !string.IsNullOrWhiteSpace(x.title))
.Count();
You could get the count of closed like this:
int closedCount = ORCollection
.Where(x => x.status == status.CLOSED)
.Count();
If you were going to have larger collections or you access the values a lot it might be worth creating a custom collection implementation that stores the field counts, it could then increment/decrement these values as you add and remove items. You could also store a dictionary of status counts in this custom collection that gets updated as you add and remove items.

Remove items from a dictionary based on listbox selection

I have a listbox that prints the name of a custom item class
public class Item
{
public string #Url { get; set; }
public string Name { get; set; }
public double Price { get; set; }
public Item(string #url, string name, double price)
{
this.Url = url;
this.Name = name;
this.Price = price;
}
public override string ToString()
{
return this.Name;
}
}
I tried the normal method but because i have radio buttons to sort the list box it messes it up since index is changed.
EG
//new item is declared
Dictionary<int, Item> itemList = Dictionary<int, Item> { new Item("f.ca", "name1", 33);
new Item("m.ca", "name2", 44); }
//Items added to listbox
for (int v = 0; v < itemList.Count; v++)
{
itemListBox.Items.Add(itemList[v].Name);
}
//start sorting
var priceSort = from item in itemList
orderby item.Value.Price
select new { item.Value.Name, item.Value.Price };
itemListBox.Items.Clear();
foreach (var i in priceSort)
{
itemListBox.Items.Add(i.Name);
}
//end sorting listbox updated
now that the new list is created removing only the item in itemlist is necessary since the box is updated.
/* This code is what i thought but SelectedIndex say if on 0 and since the sorted by price */
itemList.Remove(itemListBox.SelectedIndex);
The issue being now its trying to remove items[0] when items[1] is really the one that needs to be removed. Is there a way i could make it compare the string of the itemlistbox to the .Name property of the items dictionary?
You stated that the key for your dictionary is determined by the current count of items in the dictionary. If that's the case, you'd have to do something like this:
var matches = itemList.Where(x => x.Name == itemListBox.SelectedValue);
if (matches.Any())
{
itemList.Remove(matches.First().Key);
}
But this is slow and inelegant. You're really not using the Dictionary class correctly. Dictionaries are ideal for performing quick access based on a known key value. If you have to search for the key every time, you loose all benefit the Dictionary provides.
You might as well use a simple List<Item> instead, using the FindIndex / RemoveAt methods:
var index = itemList.FindIndex(x => x.Name == itemListBox.SelectedValue);
if (index != -1)
{
itemList.RemoveAt(index);
}
This isn't a whole lot faster, but it's more elegant—lists are specifically designed to support this kind of thing without having to resort to Linq.
Or better yet, use the item's name as the dictionary key:
Dictionary<string, Item> itemList = Dictionary<string, Item>();
itemList.Add("name1", new Item("f.ca", "name1", 33));
itemList.Add("name2", new Item("m.ca", "name2", 44));
...
itemList.Remove(itemListBox.SelectedValue);
This is a much more efficient and elegant solution.

Categories