How to apply ordered values to the same BindingList? - c#

I have got:
var orderedStatItmes = item.Statistics.OrderByDescending(t=>t.StartTime);
Note that
public BindingList<IStatistics> Statistics { set; get; }
What I need is the best way to reassign orderedStatItmes to item.Statistics so it should be in place.
How to do it?
Thanks!!

I can't say I've used BindingList<T> much at all myself.
You may be better off sorting the underlying collection, if you've got access to that. Alternatively, if the BindingList<T> itself supports sorting, you might want to use IBindingList.ApplySort.
One horribly hacky way of doing it would be:
var ordered = item.Statistics.OrderByDescending(t => t.StartTime).ToList();
for (int i = 0; i < ordered.Count; i++)
{
item.Statistics[i] = ordered[i];
}
... but I wouldn't like to say what that will do to any bindings while it's updating.
Old answer (before question was edited to mention BindingList<T>)
Do you mean you need to mutate the existing array, or are you happy to just assign a new array reference to the item.Statistics property? If it's the latter:
item.Statistics = item.Statistics.OrderByDescending(t=>t.StartTime).ToArray();
If you want to basically sort the array (I'm assuming it's an array, based on your question title) in place, you could use:
Array.Sort(item.Statistics, (x, y) => x.StartTime.CompareTo(y.StartTime));

Related

list property containing two types (string/int)

I need to have a property that will be an array that can hold both ints and strings.
if i set the property to an array of ints it should be ints so when I am searching through this array the search will be fast, and at odd times this property will also contain strings which the search will be slow.
Is there any other way other than the following to have a list that contain native types
two properties one for ints and one for strings
use List< object >
UPDATE:
The use-case is as follow. I have a database field [ReferenceNumber] that holds the values (integers and strings) and another field [SourceID] (used for other things) which can be used to determine if record holds an int or string.
I will be fetching collections of these records based on the source id, of course depending on what the source is, the list either will be integers or strings. Then I will go through this collection looking for certain reference numbers, if they exist not add them or they dont then add them. I will be pre-fetching a lot of records instead of hitting the database over and over.
so for example if i get a list for sourceid =1 that means they are ints and if searching i want the underline list to be int so the search will be fast. and if sourceid say is 2 which means they are strings and very rare its okay if the search is slow because those number of records are not that many and a performance hit on searching through strings is okay.
I will go through this collection looking for certain reference numbers, if they exist not add them or they dont then add them.
It sounds to me like you don't need a List<>, but rather a HashSet<>. Simply use a HashSet<object>, and Add() all the items, and the collection will ignore duplicate items. It will be super-fast, regardless of whether you're dealing with ints or strings.
On my computer, the following code shows that it takes about 50 milliseconds to populate an initial 400,000 unique strings in the hashset, and about 2 milliseconds to add an additional 10,000 random strings:
var sw = new Stopwatch();
var initial= Enumerable.Range(1, 400000).Select(i => i.ToString()).ToList();
sw.Start();
var set = new HashSet<object>(initial);
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
var random = new Random();
var additional = Enumerable.Range(1, 10000).Select(i => random.Next(1000000).ToString()).ToList();
sw.Restart();
foreach (var item in additional)
{
set.Add(item);
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
Also, in case it's important, HashSet<>s do retain order of insertion.
The only other thing I would suggest is a custom object that implements IComparable
class Multitype: IComparable
{
public int? Number { get; set; }
public string Words {get; set; }
public int CompareTo(object obj)
{
Multitype other = obj as Multitype;
if (Number != null && other != null && other.Number != null)
{
//...
}
else
{
//...
}
}
}
There will be some extra comparison steps between numbers, but not as much as string parsing.
Are you storing a ton of data, is that performance difference really going to matter?
It's possible to use generics if you implement them on the class. Not sure if this solves your problem. Would be interested to hear the real-world example of a property that can have different types.
class Foo<T>
{
public List<T> GenericList { get; set; }
public Foo()
{
this.GenericList = new List<T>();
}
}
If by "use List" you mean the object primitive or provided System.Object, that is an option, but I think it would behoove you to make your own wrapper object -- IntString or similar -- that would handle everything for you. It should implement IComparable, as the other gal mentioned.
You can increase the efficiency of sorting your object in collections by writing a CompareTo method that does exactly what you need it to. Writing a good CompareTo method is a whole can of worms in itself, so you should probably start a new question for that, if that's what you want.
If you're looking for a property that is strongly typed as a List<Int> or List<String> at instantiation, but can change afterwards, then you want an interface. IList exists, but won't help you, since that must also be strongly typed upon declaration. You should probably make something like IIntStringList that can only be one of List<Int> or List<String>.
Sorry this answer doesn't have that many details (I need to leave the office now), but I hope I've set you on the right track.

Linq to SQL: Equivalent of Array.SequenceEqual

Let's say I have this method:
public T GetByID(object[] pKeys)
{
DbQuery<T> dbq = mContext.GetDbSet<T>();
return dbq.SingleOrDefault(ent => ent.PrimaryKey.SequenceEqual(pKeys));
}
ent.PrimaryKey is an object[].
Of course, this doesn't work because of the SequenceEqual(). I could maybe use Contains but this would not preserve order: {1, 2} is NOT equal to {2, 1}.
I could also use AsEnumerable() first and then use some logics but that would load the whole table in memory, which is unacceptable.
Is there a way to achieve this?
Edit
I've made the method generic. Because that's what it really is and it makes more sens with the primary key being an array.
I also point out that the goal of the method here could be achieved with mContext.GetDbSet().Find(pKeys). This, however, complicates the use of dbq.Include(property) or mContext.Entry(wanted).Collection(property).Load() for parent.child properties which is another matter not related to the question.
Without reproducible code it is a little tough to test any particular solution, but the first thing that came to my mind (and compiled/tested in notepad) is
public T GetByID(object[] pKeys)
{
DbQuery<T> dbq = mContext.GetDbSet<T>();
for (var i = 0; i < pKeys.length; i++)
{
dbq = dbq.Where(ent => ent.PrimaryKey[i] == pKeys[i]);
}
return dbq.SingleOrDefault();
}

C# List removeall taking two arguments in the predicate?

(I've done as much as possible search based on keywords of "removeall where" or "removeall two argument predicate" without much luck so here goes)
The problem is I have a list of objects (of Class Wave) and a relationship function as:
private bool AinB(Wave A, Wave B), returning true if A 'is in' B. Also AinB(x,y) is true guarantees AinB(y,x) is false.
What's the best way to remove all of the objects in the list where the objects 'is in' another object in the list? i.e., after the removal, the list should only contain objects where neither are in the 'is in' relationship with any other object in the list?
ideally this can be done easily as a
listX.RemoveAll( (x,y) => AinB(x,y)) but of course this is not legal in C#, also there's no easy way to specify which to remove, x or y.
I thought about looping through the list with an index
int i = listX.Count - 1;
while (i>=0)
{
int r = listX.RemoveAll(X => AinB(X, listX[i]));
i = i - r - 1;
}
This seems to work, but I am wondering if there's better way with straight linq code to solve the problem.
Thanks.
Unfortunately I can't think of any way to do this that's not at least O(n^2). But the good news is that it's not that hard from a LINQ perspective:
listX.RemoveAll(item => listX.Any(isin => AinB(item, isin)));
Use a normal for loop that inspects the highest element first down to the lowest element in the list. Inspect the element at the current position for any duplicates within the list, if found remove the current element (and possibly decrement your iterator).
Example:
List<string> stuff = new List<string>(); //full of stuff
for(int i = stuff.Count - 1; i > 0; i--)
{
//Edited here for more efficiency.
for (int x = i - 1; x > 0; x--)
{
if (stuff[x] == stuff[i])
{
stuff.RemoveAt(i);
break; //or possibly continue;
}
}
}
This was hand-coded here so it might have a few syntactical errors, feel free to shoot me an edit if you find something's not quite right.
If you're a wizard with LINQ you could also try grouping the objects in the list and then just selecting the first object in each group for your output list..
you can use the LINQ Except call,
List a = new List();
a.Add("a");
a.Add("b");
a.Add("c");
List b = new List();
b.Add("b");
b.Add("c");
b.Add("d");
List c = a.Except(b);
list c will contain only item "a";
you can even make it more clever by giving a compare object,
List c = a.Except(b, new CompareObject());

Find max value of two (or more) properties in list

This question has been asked in one or the other way on SO but not like this. I just came over a very basic issue where I was looking for a statisfying solution :-)
I got a list of objects which have two integer properties. Now I want to find the max value of both properties of all object in the list.
I came up with three solutions:
First approach:
int max = Math.Max(list.Max(elem => elem.Nr), list.Max(elem => elem.OtherNr));
Second approach:
public int Max(List<Thing> list)
{
int maxNr = 0;
foreach (var elem in list)
{
if (elem.Nr > maxNr)
maxNr = elem.Nr;
if (elem.OtherNr > maxNr)
maxNr = elem.OtherNr;
}
return maxNr;
}
A third approach would be to do the sorting by both attribute and then just take the first entry and get the one or the other property.
I would like to find the fastest way to do this. So of all approaches I like the second one the post (from the performace point of view). Even though the first one is shorter you have to go through the list twice.
Any other solutions?
If you do
int max = list.Max(elem => Math.Max(elem.Nr, elem.OtherNr));
it's still a single-liner but only iterates through the list once. I'd take the single-linedness over the probable slight reduction in efficiency from writing it out by hand.
(Also, don't you need a cast from double to int somewhere in there?)
An alternative solution using LINQ if you need more than 2 properties (which is the limit of Math.Max):
int max = list
.SelectMany(elem => new[]{ elem.Prop1, elem.Prop2, elem.Prop3 })
.Max();

List of classes question c#

I have a class contain many variables, something like that
class test
{
internal int x , y ;
internal string z;
}
I created a list of this class list<test> c
I want to do the following:
test if all the list items contain the same x
get the list's item that has z = "try"
I need a quick and fast way , instead of iterate though the entire items
Any suggestion please ,
LINQ to Objects is your friend. For the first:
bool allSameX = list.All(t => t.x == list[0].x);
Test firstTry = list.First(t => t.z == "try");
Test firstTryOrNull = list.FirstOrDefault(t => t.z == "try");
The first one depends on there being at least one value of course. Alternatives might be:
bool allSameX = !list.Select(t => t.x)
.Distinct()
.Skip(1)
.Any();
In other words, once you've gone past the first distinct value of x, there shouldn't be any more. One nice aspect of this is that as soon as it spots the second distinct value, it will stop looking - as does the first line (the All version) of course.
LINQ is wonderfully flexible, and well worth looking into closely.
EDIT: If you need to do the latter test ("find an element with a particular value for z") for multiple different values, you might want a dictionary or a lookup, e.g.
// If there are duplicate z values
var lookup = list.ToLookup(t => t.z);
// If z values are distinct
var dictionary = list.ToDictionary(t => t.z);
Without some pre-work, there's no way of performing the queries you want without iterating over at least some of the list.
You can use linq. Here is a link to small examples that will help you a lot for future too http://msdn.microsoft.com/en-us/vcsharp/aa336746
You could implement a custom collection class instead of a list, and put the search smarts into this e.g.
add a method AllItemsHaveSameX() and a private bool field allItemsHaveSameX
expose a dictionary keyed by the search strings with the index of the item that has that value.
When adding/removing items:
You would re-evaluate allItemsHaveSameX
Add/remove from your private dictionary.

Categories