1

I have a folder with several Directories that are named after a version of an update such as UPDATE_20080311_3.5.9. I need to find the latest update on that list by veryfing the "3.5.9", I made a code to parse the name and add just the version to a list. Is there anyway to Sort tha list by using List.Sort in order to get the latest version "number"? This is the code I made so far, I don't know how to properly use the .Sort() method and if this can be done. I appreciate any help given

public string NewerVersion(string Directoria)
    {
        List<string> Lista = new List<string>();
        DirectoryInfo dir = new DirectoryInfo(Directoria);
        DirectoryInfo[] dirs = dir.GetDirectories();
        foreach (DirectoryInfo Info in dirs)
        {
            string Dir = Info.Name.ToString();
            Lista.Add(Dir.Substring(Dir.LastIndexOf('_'), Dir.Length));

        }
        Lista.Sort()
        //Lista.ToArray();
    }
Mr.Toxy
  • 357
  • 4
  • 19

5 Answers5

3

You can use Version which implements IComparable, so it supports sorting.

For example with this LINQ query:

Version version = null;
Version lastVersion = new DirectoryInfo(Directoria).EnumerateDirectories()
    .Where(d => d.Name.StartsWith("UPDATE_"))
    .Select(d => new {Directory = d, Token = d.Name.Split('_')})
    .Where(x => x.Token.Length == 3 && Version.TryParse(x.Token[2], out version))
    .Select(x => new {x.Directory, Date = x.Token[1], Version = version})
    .OrderByDescending(x => x.Version)
    .Select(x => x.Version)
    .FirstOrDefault();
string latestVersion = lastVersion.ToString(); // if you want it as string

After I find the newer version I need to be able to return the name of the directory

Then use this query:

var lastVersion = new DirectoryInfo(Directoria).EnumerateDirectories()
    .Where(d => d.Name.StartsWith("UPDATE_"))
    .Select(d => new {Directory = d, Token = d.Name.Split('_')})
    .Where(x => x.Token.Length == 3 && Version.TryParse(x.Token[2], out version))
    .Select(x => new {x.Directory, Date = x.Token[1], Version = version})
    .OrderByDescending(x => x.Version)
    .FirstOrDefault();
if (lastVersion != null)
    Console.WriteLine(lastVersion.Directory.FullName);
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
  • Was just about writing an answer with shitty splits and text sortings. Holy shit havnt known there is a `Version` class. Thanks! – C4d Apr 12 '16 at 15:13
  • After I find the newer version I need to be able to return the name of the directory – Mr.Toxy Apr 12 '16 at 15:22
  • @Mr.Toxy: Done. Note that you also could check if there's a version that is greater than(or equal to) `3.5.9`. You just need to modify the `Where` in this way: `.Where(x => x.Token.Length == 3 && Version.TryParse(x.Token[2], out version) && version >= new Version("3.5.9"))` (initialize it once in a variable before the query). – Tim Schmelter Apr 12 '16 at 15:31
  • @TimSchmelter sorry for the ignorance but Im a little lost. The only difference between the two queries that you mentioned are what they return right? – Mr.Toxy Apr 12 '16 at 15:35
  • @TimSchmelter will this method also work for newer versions like 4.1.1 or any other.? Let's assum that this will have to work for any version – Mr.Toxy Apr 12 '16 at 15:38
  • Of course it will work, and yes, the second query is just a little modification. You already have all you need in the anonymous type – Tim Schmelter Apr 12 '16 at 17:49
  • @TimSchmelter on this line .Select(x => new {x.Directory, Date = x.Token[1], Version = version}) where the Version = version is, the "version" variable appears as not initialized – Mr.Toxy Apr 13 '16 at 08:29
  • @Mr.Toxy: you mean you get a compiler error? Then you haven't used my current code where i initialize it with null: `Version version = null;`. That it gets a valid version is ensured with the second condition in the `Where`: `Version.TryParse(x.Token[2], out version)` – Tim Schmelter Apr 13 '16 at 08:30
  • @TimSchmelter oups, ur right. I totally missed that reference. Thank you :D – Mr.Toxy Apr 13 '16 at 08:45
  • @TimSchmelter sorry to bother so mucch but I never used Linq before and its kind of confusing to me. Some of the changes that they asked me to do is to find the newest setup out of a list with folders named like this: Setup15, Setup14, Setup16... Hoe can I adapt your code in order to find the newest as we did above? – Mr.Toxy Apr 13 '16 at 09:01
  • Replace `UPDATE_` with `Setup` and use `int.Parse` to convert the substring to an `int` which you can use for the order. If you don't know what to do create another question and explain it well. If you post a comment with the link to that question here i can try to answer it. – Tim Schmelter Apr 13 '16 at 10:47
  • @TimSchmelter http://stackoverflow.com/questions/36597030/searching-for-the-newest-update-in-a-directory-c-sharp Done ;) – Mr.Toxy Apr 13 '16 at 11:30
2

When sorting by version, try using Version which is specially designed for that:

 List<String> Lista = new List<string>() {
    "UPDATE_20080311_3.5.9",
    "UPDATE_20080311_3.5.10",
    "UPDATE_20080311_3.4.11",
  };

  Lista.Sort((left, right) => {
    Version x = new Version(left.Substring(left.LastIndexOf('_') + 1));
    Version y = new Version(right.Substring(right.LastIndexOf('_') + 1));

    // or "return -x.CompareTo(y);" if you want to sort in descending order
    return x.CompareTo(y);
  });

  ...

  // UPDATE_20080311_3.4.11
  // UPDATE_20080311_3.5.9
  // UPDATE_20080311_3.5.10
  Console.Write(String.Join(Environment.NewLine, Lista);
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
  • this method will put the newer version in the first "index" of the list? Sorry for the weird question but how can I return it if its not guaranteed that a list is orderly searched? – Mr.Toxy Apr 12 '16 at 15:18
  • @Mr.Toxy, no the *older* one will be on the *top*, to reverse (sort in *descending order*) put `-` before `x.CompareTo(y);`: `return -x.CompareTo(y);` – Dmitry Bychenko Apr 12 '16 at 15:19
1

Edit:

Continuing from your solution, there is a problem which the way you add your item:

string Dir = Info.Name.ToString();
Lista.Add(Dir.Substring(Dir.LastIndexOf('_'), Dir.Length));

Notice two mistakes here:

  1. You get the Substring from LastIndexOf('_') instead of from LastIndexOf('_') + 1, which is what you really want
  2. You use Dir.Length while you should use Dir.Length - LastIndexOf('_') + 1 instead

Change that into:

string Dir = Info.Name.ToString();
int indexStart = Dir.LastIndexOf('_') + 1;
Lista.Add(Dir.Substring(indexStart, Dir.Length - indexStart));

Then you could further process the Lista that you have populated to have the version number alone by LINQ OrderBy and ThenBy as well as string.Split('.')

var result = Lista.Select(x => x.Split('.'))
    .OrderBy(a => Convert.ToInt32(a[0]))
    .ThenBy(a => Convert.ToInt32(a[1]))
    .ThenBy(a => Convert.ToInt32(a[2]))
    .Last();
string finalVersion = string.Join(".", result);

To get the final version among the listed items.

To get your directory path back based on your finalVersion, simply do:

string myDirPath = dirs.Select(x => x.FullName).SingleOrDefault(f => f.EndsWith(finalVersion));
Ian
  • 30,182
  • 19
  • 69
  • 107
  • In the end I need to get the full name of that directory. – Mr.Toxy Apr 12 '16 at 15:32
  • @Mr.Toxy which you do have, in your `dirs` ;) you could get it back by: `dirs.Select(x => x.FullName).SingleOrDefault(a => a.EndsWith(finalVersion));` – Ian Apr 12 '16 at 15:33
  • Firstly thank you for your help. I will test your method – Mr.Toxy Apr 12 '16 at 15:41
  • Now the only problem is my susbtring wich wont work despite everything I change to make it work correctly – Mr.Toxy Apr 12 '16 at 15:48
  • @Mr.Toxy "my substring won't work" ... won't work as in...? – Ian Apr 12 '16 at 15:49
  • @Mr.Toxy ah, I can see where you got it wrong, you use `Dir.Length` – Ian Apr 12 '16 at 15:50
  • oh yeah ahahahaha it will give an error :p it is working xD but it aint properly done – Mr.Toxy Apr 12 '16 at 15:54
  • Damn it works like a charm. Thank you so so much, you've spare me some more headicks thx so much :D – Mr.Toxy Apr 12 '16 at 16:03
  • 1
    @Mr.Toxy no problem. ;) be careful of the string position when you use `Substring`. It often confusing. :) – Ian Apr 12 '16 at 16:03
  • can you shed some light on this pls: http://stackoverflow.com/questions/36570501/updating-a-config-file-in-c-sharp – Mr.Toxy Apr 13 '16 at 08:27
  • @Mr.Toxy ugh... it seems like it is problem of XML... I know the tool, by I myself seldom use it. read your XML using `XmlDocument doc = new XmlDocument();` then use some items in the XML parser to handle the files further... – Ian Apr 13 '16 at 08:33
  • sorry to bother you so damn much but I never used Linq before and it's hard to understand at first for me, I've analyzed the code but can't fully understand. Some of the changes that they asked me to do is to find the newest setup out of a list with folders named like this: Setup15, Setup14, Setup16... Hoe can I adapt your code in order to find the newest as we did above? – Mr.Toxy Apr 13 '16 at 09:40
1

You can use Linq and Version

public string NewerVersion(string Directoria)
{
    return new DirectoryInfo(Directoria)
        .GetDirectories()
        .OrderByDescending(x => new Version(x.Name.Substring(x.Name.LastIndexOf('_') + 1)))
        .First()
        .Name;
}

If Directoria contains "UPDATE_20080311_3.5.9", "UPDATE_20090311_5.6.11", "UPDATE_20070311_1.5.9", will return "UPDATE_20090311_5.6.11"

klev
  • 622
  • 7
  • 10
0

I'm not sure about, whether this satisfies the requirement or not;if not please forgive me;

You are creating folders for each version release; so a version 3.5.7 will be created after 3.5.6 which is followed by 3.55 and the next version could be 3.58, So what i'am trying to say is that, they can be sorted on the basics of creation time. if so the following code will help you:

public static string NewerVersion(string Directoria)
{
    List<string> Lista = new List<string>();
    DirectoryInfo dir = new DirectoryInfo(Directoria);
    DirectoryInfo[] dirs = dir.GetDirectories();
    Lista = dirs.OrderBy(x => x.CreationTime).Select(y => y.Name.ToString()).ToList();
    //Lista will contains the required names
    //rest of code here
    return String.Join(Environment.NewLine, Lista);
}
sujith karivelil
  • 28,671
  • 6
  • 55
  • 88
  • Thank you for you answer. I dont think this method will work because I dont know how they deploy the versions. They just told me to search the newest by the version "number". – Mr.Toxy Apr 12 '16 at 15:31