Getting all folders in specific order
Asked Answered
C

3

5

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)

Chrisom answered 19/10, 2010 at 20:26 Comment(2)
It's unclear what order you would like to see them in. Why shouldn't "2A" be checked before "z" since you stated "0-10", then "a-z"? Can you give an example directory structure and in what order they should be iterated over?Taenia
Oop, meant 0-9. Base36 goes 0,1,2,3..9,a,b,c,d,e..z,10,11,12..,1a,1b,1c..1z,20,21,22...etcChrisom
G
3

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
Granddad answered 19/10, 2010 at 20:31 Comment(1)
I like this solution. Taking two passes will make it very simple. @Philips is impressive but overly complex compared to this.Brocket
B
5

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;
}
Bren answered 19/10, 2010 at 20:32 Comment(0)
G
3

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
Granddad answered 19/10, 2010 at 20:31 Comment(1)
I like this solution. Taking two passes will make it very simple. @Philips is impressive but overly complex compared to this.Brocket
B
1

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...

Brocket answered 19/10, 2010 at 20:26 Comment(1)
Convert.ToInt32 specifies that base must be 2,8,10,or 16.Bren

© 2022 - 2024 — McMap. All rights reserved.