Search code examples
c#arraysstring-comparison

Searching through a list of strings and looking for file versions that need to be updated


I have two string arrays, one is of all the calendar versions that the local computer has, the other is of all the versions that an ftp server has. I know how to fill both arrays, I just don't know how to compare them to look for versions that are out of date.

I need to look through the local computer array (strings look like: date1-date2-version e.g. 2021-2022-3), and return an array of strings of files that need to be updated.

A few situations that also need to be addressed by this code:

  1. If a calendar is in the ftp server, and is not on the local computer, but is below the highest calendar date (not version), which is stored in a string called mostRecentCalender, then that calendar does not need to be added to the array.
  2. If the local computer has a calendar version that is multiple versions behind, the code needs to only add the highest version.

Example of ftp folders array:

  1. 2019-2020-1
  2. 2019-2020-2
  3. 2020-2021-1
  4. 2020-2021-2
  5. 2020-2021-3
  6. 2020-2021-4
  7. 2021-2022-1

Example of local folders array:

  1. 2020-2021-1
  2. 2020-2021-2

Example of results of versions that need to be updated (plus explanation):

  1. 2020-2021-4 (this was added to the array because they have the calendar year 2020, but the version was out of date, so it added the most recent of that year, ignoring the version 2020-2021-3, as it is unnecessary.
  2. 2021-2022-1 (this was added to the array because it is equal to the year and version of the string called mostRecentCalendar. Versions 2019-2020-1 and 2019-2020-2 were ignored, as they do not have any calendars in the year 2019, and they are below the year for of the mostRecentCalendar string.

Solution

  • Let's reduce the ftp folders to only the highest versions:

    var maxFtps = ftpArray
      .GroupBy(x => x[..9], x => int.Parse(x[10..]))
      .Select(g => (Year: g.Key, Ver: g.Max()))
    

    This pulls the first 9 chars off every string (so the year-year part) and also pulls for char 10 onwards and parses to int The entries are grouped on the years so your example will reduce to 3 entries and each grouping will be a sequence of ints which is the version

    Next we select just the key and the max version int to produce some temporary ValieTuple objects like:

    "2019-2020", 2
    "2020-2021", 4
    "2021-2022", 1
    

    Now, we don't need to be so technical for the locals. Essentially we only need to look up if a Year prefix exists locally to know what to do with the ftp version

    var localYears = localsArray.Select(x => x[..9]).ToHashSet();
    

    We make a hashset to store the output, as it will automatically dedupe

    var localHash = localsArray.ToHashSet();
    

    Then we can make a decision on each of the max ftps- add it if it's known locally or if it's the most recent

    foreach(var m in maxFtps)
    {
        var recomposed = m.Year + "-" + m.Ver;
        
      //add it if its a known local year - hashset will auto dedupe
      if(localYears.Contains(m.Year))
        localHash.Add(recomposed);
    
      //or if this ftp entry represent the most recent
      if(recomposed == mostRecentCalender)
        localHash.Add(mostRecentCalender);
        
    }
    

    I realized that you didn't specify what is to happen if there is eg a mostRecentCalender of "2021-2022-4", a local of "2021-2022-1" and an ftp of "2021-2022-2". The code as it stands will add the ftp version even though it's not the most recent. You might have to tweak the logic if you don't want to add