0

Is there an easy way to influence the processing sequence of an ObservableCollection in c#?

Lets say I have the following class:

public class GeneratorObject : IComparable
{
        int processingSequence {get; set;}
        string property1 {get; set;}
        Boolean property2 {get; set;}

        public GeneratorObject(int processingSequence)
        {
            this.processingSequence = processingSequence;
        }

        public int CompareTo(object obj)
        {
             // Implementation
        }               
}

The processing sequence could be every natural number.

I want to iterate some of some of them

ObservableCollection<GeneratorObject> toIterate = new ObservableCollection<GeneratorObject>();

toIterate.Add(new GeneratorObject(99));
toIterate.Add(new GeneratorObject(1));
toIterate.Add(new GeneratorObject(10));
toIterate.Add(new GeneratorObject(6));

foreach (GeneratorObject field in toIterate)
{
    // Manipulating the properties of field
}

I dont really want to sort the Collection, espeacially in the view. I just want to change the order for the iteration. First the element with the lowest sequence number, ..., Furthermoore it is important to say, that im manipulating the items while iterating and could not just use a copy of the collection.

Ive already implemented IComparable and thought i could easy say e.g. Collection.Sort() without destroying the binding with the UI.

Thanks for any help.

theawak3r
  • 7
  • 4
  • What have you tried? The painfully obvious answer is to sort a copy of the collection (as -- eventually -- recommended by the one answer posted below). Any reason you're not doing that? Please be more specific, and provide a good [mcve] that shows clearly what you've tried, explain what _specifically_ you are having trouble with. – Peter Duniho Mar 20 '17 at 06:54
  • Thanks for the advise. Ill try to be more specific the enxt time. The problems of not coping is, that im manipulating the items while iterating. – theawak3r Mar 20 '17 at 07:09
  • Please edit your question to provide clarifications. Note that even with your clarification, the question is still to broad. That said, while you could maintain a sorted array of indexes into the underlying collection, if you are changing the collection while you iterate, you should probably just do a linear scan on the collection each time you want to perform your operation on the lowest sequence #, to find that lowest #. – Peter Duniho Mar 20 '17 at 07:14
  • Another alternative would be to add a property to the `GeneratorObject` that maintains the display order, and keep the collection in sequence # order. Then use WPF's built-in `CollectionViewSource` to sort the display by the display order property #. – Peter Duniho Mar 20 '17 at 07:14
  • Could you please try to clarify your way of a sorted array of indexes and the underlying collection? – theawak3r Mar 20 '17 at 07:24
  • See http://stackoverflow.com/q/19064472, http://stackoverflow.com/q/34090307, and http://stackoverflow.com/a/37359265 for examples. The first two use the `Array.Sort()` overload that helps with this approach, while the third is an answer I posted last year that does it more explicitly. That said, I wouldn't recommend it. You can find the min value in O(n) time, but a sort costs O(n log n). Even if you defer the sort until you need to pick the next item, it costs more than a linear search, and if you sort every time the original collection changes, it's even worse. – Peter Duniho Mar 20 '17 at 07:39

3 Answers3

0

You can create a copy of the list, sort it and then iterate the copy list:

        //ObservableCollection<GeneratorObject> toIterate;
        // I am assuming that 'toIterate' is not null and bound to the UI
        toIterate.Add(new GeneratorObject(99));
        toIterate.Add(new GeneratorObject(1));
        toIterate.Add(new GeneratorObject(10));
        toIterate.Add(new GeneratorObject(6));

        var copy = toIterate.ToList();
        copy.Sort();

        foreach (GeneratorObject field in copy)
        {

        }

The sort action here is executed on a different list so it won't change the order in the UI.

elirandav
  • 1,913
  • 19
  • 27
  • Thanks for the answer. The problem is, that im manipulating the objects while iterating. I also had this idea to copy but then im loosing the reference to the real objects. – theawak3r Mar 20 '17 at 07:08
0

If the list is changing while you are iterating, then instead of iterating, you can loop until the list is empty, and find the min every iteration.

while (toIterate.Any())
{
    GeneratorObject generatorObject = toIterate.Min();
    // do something with it
}
Ofir Winegarten
  • 9,215
  • 2
  • 21
  • 27
0

Thanks for the hint with the copy. I dont know if this is a good answer (especially regarding to performce), but i solved the problem the following way.

var copy = toIterate.ToList();
copy.Sort();

// iterate through the sorted List
foreach (GeneratorObject field in copy)
{
    // get the original object regarding to this sorted item
    GeneratorObject originalObjectForAction = getGeneratorObject(toIterate, field);
    // do stuff with the original item
}

public GeneratorObject getGeneratorObject(ObservableCollection<GeneratorObject> list, GeneratorObject objekt)
{
    foreach (DwhRoboterGeneratorObjekt field in list)
    {
        if (field == objekt) return field;
    }
    throw new Exception("Not found");
}
theawak3r
  • 7
  • 4