2

I have a unique sorting problem in which I have an array of objects that are given to me in "order" but the order is not known to me or sorted on any particular property on the object.

The object is as follows

public class Case
{
    public virtual int Id { get; set; }

    public virtual string PalletId { get; set; }
}

What I need to do is take this array of Casess that I'm given and create a new list of these objects that is sorted by the relative order of the original collections PalletId field then by it's id field. It is not an absolute ordering on this field though because it's relative to the original order of the collection.

For example:

Original Collection

Id ---------- PalletId
1 ----------- 5
2 ----------- 6
3 ----------- 4
4 ----------- 5
5 ----------- 6
6 ----------- 4

Sorted Collection

Id ---------- PalletId
1 ----------- 5
4 ----------- 5
2 ----------- 6
5 ----------- 6
3 ----------- 4
6 ----------- 4

The sorted collection above represents how I need to sort these. Notice how the palletid's in the sorted collection are not in ascending or descending order but they are sorted by the order in which you see them in the original collection (5, 6, 4). Within each pallet id I have to sort the id field in that same order. So it's the order in which I see the Id field in the original collection for a particular pallet id.

Cole W
  • 15,123
  • 6
  • 51
  • 85
  • I have edited your title. Please see, "[Should questions include “tags” in their titles?](http://meta.stackexchange.com/questions/19190/)", where the consensus is "no, they should not". – John Saunders May 28 '13 at 18:38
  • 1
    Can you elaborate on that _same relative order_ bit? – H H May 28 '13 at 18:51
  • @HenkHolterman I've modified my question a bit and the example to try and be more clear on what exactly I'm asking for. – Cole W May 28 '13 at 19:48

3 Answers3

4

After the clarification, a simple GroupBy + SelectMany seems to do the trick:

var sortedCases = originalCases
    .GroupBy(c => c.PalletId)
    .SelectMany(g => g.OrderBy(c => c.Id)) ;

As GroupBy() preserves the initial order of the keys according to this SO answer.

Community
  • 1
  • 1
H H
  • 263,252
  • 30
  • 330
  • 514
  • 1
    This seems workable. GroupBy documentation seems to support the ordering that would be useful here. – Anthony Pegram May 28 '13 at 20:25
  • This definitely gives the answer that the OP asks for. I tried it. If this is wrong, the OP should be updated with another example which shows why this won't work. – Matthew Watson May 28 '13 at 21:13
  • @MatthewWatson - The OPs top comment is in response to my first answer. I did a full rewrite, my bad. – H H May 28 '13 at 21:36
3

Use OrderBy

var orderedCases = Cases.OrderByDescending(c => c.PalletId).ThenBy(c => c.Id);
Dave Zych
  • 21,581
  • 7
  • 51
  • 66
  • 1
    As it is now, your code doesn't do anything... OrderBy uses deferred execution, and doesn't modify the source collection. – Thomas Levesque May 28 '13 at 18:42
  • @ThomasLevesque right... updated answer to assign result to a variable. If OP needs the results immediately he can call the greedy `ToList` method. – Dave Zych May 28 '13 at 18:49
  • Assigning to a variable does not cause execution. `ToList` will work, but just doing an assignment will not – Justin Pihony May 28 '13 at 18:52
  • @JustinPihony you are correct. Assigning it to a variable was in response to Thomas stating just calling OrderBy doesn't modify the source collection which he's correct about as well. – Dave Zych May 28 '13 at 18:56
  • @DaveZych This isn't exactly what I'm looking for. Please look at my example above and you will see that this wouldn't work. – Cole W May 28 '13 at 20:05
0

This gives the correct answer, but it seems a little fiddly!

It gives a different answer from Henk's in the case where the order of the Id values is descending. I think this might be what the OP is wanting, but I'm not entirely sure.

using System;
using System.Collections.Generic;

namespace Demo
{
    class Item
    {
        public int Id;
        public int PalletId;

        public override string ToString()
        {
            return string.Format("{0}, {1}", Id, PalletId);
        }
    }

    class Program
    {
        void run()
        {
            var items = new []
            {
                new Item { Id = 1, PalletId = 5},
                new Item { Id = 2, PalletId = 6},
                new Item { Id = 3, PalletId = 4},
                new Item { Id = 4, PalletId = 5},
                new Item { Id = 5, PalletId = 6},
                new Item { Id = 6, PalletId = 4}
            };

            sortItems(items);
            items.Print();
        }

        void sortItems(Item[] items)
        {
            for (int i = 0, j = 1; i < items.Length && j < items.Length; i = j, j = i + 1)
            {
                while ((j < items.Length) && (items[i].PalletId == items[j].PalletId))
                    ++j;

                for (int k = j+1; k < items.Length; ++k)
                {
                    if (items[k].PalletId == items[i].PalletId)
                    {
                        move(items, j, k);
                        break;
                    }
                }
            }
        }

        void move(Item[] items, int to, int from)
        {
            var temp = items[from];

            for (int i = from; i > to; --i)
                items[i] = items[i-1];

            items[to] = temp;
        }

        static void Main()
        {
            new Program().run();
        }
    }

    static class DemoUtil
    {
        public static void Print(this object self)
        {
            Console.WriteLine(self);
        }

        public static void Print(this string self)
        {
            Console.WriteLine(self);
        }

        public static void Print<T>(this IEnumerable<T> self)
        {
            foreach (var item in self) Console.WriteLine(item);
        }
    }
}
Matthew Watson
  • 104,400
  • 10
  • 158
  • 276