tags:

views:

44

answers:

3

I have a list of folders that are organised by base36 (0-9 then a-z). Now my current implementation for reading them is to iterate over a number, convert it to base32, check if the folder exists. If it does read the data if it doesn't end.

The problem here is that there are gaps in the folder's numbers. Ex: 0,1,2,4,5,6,8,a,b,c,g,k,p

What would be the best way of iterating over them all, in the correct order (considering there can be any amount of folders)?

(Note: I can't simply get all of the directories, because they'd be ordered alphabetically. 2A for example would be placed before z)

+3  A: 

This is effectively a radix sort on your folder names. Sort them all alphabetically first, then sort that by the length of the string.

var names = new[] {"4cc", "2a", "0", "z", "1ab"};

foreach (var n in names.OrderBy(x => x).OrderBy(y => y.Length)) 
{
    Console.WriteLine(n);
}

Yields:

0
z
2a
1ab
4cc
Austin Salonen
I like this solution. Taking two passes will make it very simple. @Philips is impressive but overly complex compared to this.
Abe Miessler
Got to agree with the above, thanks :)
Blam
+4  A: 

I would probably get all directories into memory, and then sort them rather than try to create something that would guess all possible values in order.

var names = GetAllDirectoryNames();
names.Sort(CompareNames);
foreach( var name in Names)
{
  DoSomethingWithDir(name);
}

//...

private static int CompareNames(string x, string y)
{
  if( x == null && y == null) return 0;
  if( x== null) return -1;
  if( y == null) return 1;

  var xVal = Base36Decode(x);
  var yVal = Base36Decode(y);
  if( xVal > yVal) return 1;
  if( xVal < yVal) return -1;
  return 0;
}

private long Base36Decode(string inputString)
{
    var charList = "0123456789abcdefghijklmnopqrstuvwxyz";

    inputString = Reverse(inputString.ToLower());
    long result = 0;
    int position = 0;
    foreach (char c in inputString)
    {
        result += charList.IndexOf(c) * (long)Math.Pow(36, position);
        position++;
    }
    return result;
}
Philip Rieck
Very nice, thanks.
Blam
+1  A: 

Try this to get them in order:

List<string> b36Items = new List<string>;
//Load with base 36 strings;

List<string> sortedItems = b36Items.OrderBy( t=> Convert.ToInt32(t,36)).ToList();

Documentation for the Convert.ToInt32(string, base) here.

UPDATE

As @Philip Rieck pointed out this will not work with base 36 since the highest base this function works with is 16. I will leave it up for other people who have a similar issue with a smaller base, but you are better off using one of the other solutions. Too bad because this would have been pretty slick...

Abe Miessler
Need to add a ToList
David B
That makes a lot more sense.
Blam
Convert.ToInt32 specifies that base must be 2,8,10,or 16.
Philip Rieck
Good catch. I missed that.
Abe Miessler