Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I order this list of site URLs in C#?

Tags:

c#

linq

I have a list of site URLs,

  • /node1
  • /node1/sub-node1
  • /node2
  • /node2/sub-node1

The list is given to me in a random order, I need to order it so the the top level is first, followed by sub-levels and so on (because I cannot create /node2/sub-node1 without /node2 existing). Is there a clean way to do this?

Right now I'm just making a recursive call, saying if I can't create sub-node1 because node2 exists, create node2. I'd like to have the order of the list determine the creation and get rid of my recursive call.

like image 840
chum of chance Avatar asked Jun 14 '13 16:06

chum of chance


3 Answers

My first thought was ordering by length of the string... but then I thought of a list like this, that might include something like aliases for short names:

/longsitename/  
/a  
/a/b/c/  
/a  
/a/b/  
/otherlongsitename/  

... and I thought a better option was to order by the number of level-separator characters first:

IEnumerable<string> SortURLs(IEnumerable<string> urls)
{
    return urls.OrderBy(s => s.Count(c => c == '/')).ThenBy(s => s);
}

Then I thought about it some more and I saw this line in your question:

I cannot create /node2/sub-node1 without /node2 existing

Aha! The order of sections or within a section does not really matter, as long as children are always listed after parents. With that in mind, my original thought was okay and ordering by length of the string alone should be just fine:

IEnumerable<string> SortURLs(IEnumerable<string> urls)
{
    return urls.OrderBy(s => s.Length);
}

Which lead me at last to wondering why I cared about the length at all? If I just sort the strings, regardless of length, strings with the same beginning will always sort the shorter string first. Thus, at last:

IEnumerable<string> SortURLs(IEnumerable<string> urls)
{
    return urls.OrderBy(s => s);
}

I'll leave the first sample up because it may be useful if, at some point in the future, you need a more lexical or logical sort order.

like image 145
Joel Coehoorn Avatar answered Oct 21 '22 13:10

Joel Coehoorn


Is there a clean way to do this?

Just sorting the list of URI's using a standard string sort should get you what you need. In general, "a" will order before "aa" in a string sort, so "/node1" should end up before "/node1/sub-node".

For example:

List<string> test = new List<string> { "/node1/sub-node1", "/node2/sub-node1", "/node1",  "/node2"  };

foreach(var uri in test.OrderBy(s => s))
   Console.WriteLine(uri);

This will print:

/node1
/node1/sub-node1
/node2
/node2/sub-node1
like image 44
Reed Copsey Avatar answered Oct 21 '22 14:10

Reed Copsey


Perhaps this works for you:

var nodes = new[] { "/node1", "/node1/sub-node1", "/node2", "/node2/sub-node1" };
var orderedNodes = nodes
    .Select(n => new { Levels = Path.GetFullPath(n).Split('\\').Length, Node = n })
    .OrderBy(p => p.Levels).ThenBy(p => p.Node);

Result:

foreach(var nodeInfo in orderedNodes)
{
    Console.WriteLine("Path:{0} Depth:{1}", nodeInfo.Node, nodeInfo.Levels);
}

Path:/node1 Depth:2
Path:/node2 Depth:2
Path:/node1/sub-node1 Depth:3
Path:/node2/sub-node1 Depth:3
like image 37
Tim Schmelter Avatar answered Oct 21 '22 12:10

Tim Schmelter