Reputation: 1070
I have a list of FTPFileItems objects that I need to sort and get the latest version based on the Version in the filename.
class FtpFileInfo
{
string FileName;
DateTime FileDate;
long FileSize;
FtpFileType FileType;
}
Example Filename Data in each object
FileName = "XXX_AE_V1_20160812132126.xml"
FileName = "XXX_AE_V2_20160912142126.xml"
FileName = "XXX_AE_V3_20161012152126.xml"
FileName = "XXX_AU_V1_20190213142439.xml"
FileName = "XXX_AU_V2_20190313142439.xml"
FileName = "XXX_AU_V3_20190413142439.xml"
FileName = "XXX_AU_V4_20190513142439.xml"
FileName = "XXX_BR_V1_20170828214049.xml"
FileName = "XXX_BR_V2_20170928214049.xml"
FileName = "XXX_BR_V3_20171028214049.xml"
FileName = "XXX_BR_V4_20171038214049.xml"
FileName = "XXX_BR_V6_20171048214049.xml"
I need to compress the list to the highest file version by country objects. So the list should end up like this but the complete List objects, just showing the filename part:
FileName = "XXX_AE_V3_20161012152126.xml"
FileName = "XXX_AU_V4_20190513142439.xml"
FileName = "XXX_BR_V6_20171048214049.xml"
Here is what I am trying, but I am not getting what I need. I am losing my original object because of the select and not getting highest version number.
var res = xmlFileNames.Select(s => new
{
XXX = s.FileName.Split('_')[0],
Country = s.FileName.Split('_')[1],
Version = s.FileName.Split('_')[2],
FileDate = s.FileName.Split('_')[3]
})
.OrderByDescending(x => x.Version)
.OrderBy(x => x.Country)
;
Upvotes: 0
Views: 99
Reputation: 891
I left FtpFileType out because I didn't know what a valid value is but this should do it for ya.
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public class FtpFileInfo
{
public string FileName;
public DateTime FileDate;
public long FileSize;
public object FileType;
}
public static void Main()
{
var xmlFileNames = fillClasses();
var newXmlFileNames = new List<FtpFileInfo>();
var res = xmlFileNames.Select(s => new
{
Country = s.FileName.Split('_')[1],
Version = s.FileName.Split('_')[2],
ftpFileInfo = s
}).GroupBy(x => x.Country).Select(c=> new {
country = c.Key,
ftpFileInfo = c.OrderByDescending(t=> t.Version).First().ftpFileInfo
}).ToList();
foreach(var item in res.OrderBy(c=> c.country))
{
var ftpFileInfo = new FtpFileInfo();
ftpFileInfo.FileName = item.ftpFileInfo.FileName;
ftpFileInfo.FileDate = item.ftpFileInfo.FileDate;
ftpFileInfo.FileSize = item.ftpFileInfo.FileSize;
ftpFileInfo.FileType = item.ftpFileInfo.FileType;
newXmlFileNames.Add(ftpFileInfo);
}
foreach(var newXmlFileName in newXmlFileNames)
{
Console.WriteLine(string.Format("FileName: {0} FileDate: {1} FileSize: {2}", newXmlFileName.FileName, newXmlFileName.FileDate, newXmlFileName.FileSize));
}
}
public static List<FtpFileInfo> fillClasses()
{
var ftpFileInfoList = new List<FtpFileInfo>();
var fileNames = new List<string>()
{"XXX_AE_V1_20160812132126.xml", "XXX_AE_V2_20160912142126.xml", "XXX_AE_V3_20161012152126.xml", "XXX_AU_V1_20190213142439.xml", "XXX_AU_V2_20190313142439.xml", "XXX_AU_V3_20190413142439.xml", "XXX_AU_V4_20190513142439.xml", "XXX_BR_V1_20170828214049.xml", "XXX_BR_V2_20170928214049.xml", "XXX_BR_V3_20171028214049.xml", "XXX_BR_V4_20171038214049.xml", "XXX_BR_V6_20171048214049.xml"};
foreach (var fileName in fileNames)
{
ftpFileInfoList.Add(new FtpFileInfo()
{FileName = fileName, FileDate = DateTime.Now, FileSize = 11111, FileType = null});
}
return ftpFileInfoList;
}
}
Upvotes: 0
Reputation: 2072
You are correct that the first select
statement is preventing you from maintaining the original object. My suggestion would be to group the collection by the second element (you have called this Country
). Then select the one with the highest version as shown below. Finally order by the country.
files.GroupBy(x => x.FileName.Split(new char[] { '_' })[1])
.Select(x => x.OrderByDescending(y => y.FileName.Split(new char[] { '_' })[2]).First())
.OrderBy(x => x.FileName.Split(new char[] { '_' })[1]);
A full solution is shown below with an example collection based on your example.
List<FtpFileInfo> files = new List<FtpFileInfo>() {
new FtpFileInfo { FileName = "XXX_AE_V1_20160812132126.xml" },
new FtpFileInfo { FileName = "XXX_AE_V2_20160912142126.xml" },
new FtpFileInfo { FileName = "XXX_AE_V3_20161012152126.xml" },
new FtpFileInfo { FileName = "XXX_AU_V1_20190213142439.xml" },
new FtpFileInfo { FileName = "XXX_AU_V2_20190313142439.xml" },
new FtpFileInfo { FileName = "XXX_AU_V3_20190413142439.xml" },
new FtpFileInfo { FileName = "XXX_AU_V4_20190513142439.xml" },
new FtpFileInfo { FileName = "XXX_BR_V1_20170828214049.xml" },
new FtpFileInfo { FileName = "XXX_BR_V2_20170928214049.xml" },
new FtpFileInfo { FileName = "XXX_BR_V3_20171028214049.xml" },
new FtpFileInfo { FileName = "XXX_BR_V4_20171038214049.xml" },
new FtpFileInfo { FileName = "XXX_BR_V6_20171048214049.xml" },
};
IOrderedEnumerable<FtpFileInfo> orders = files.GroupBy(x => x.FileName.Split(new char[] { '_' })[1])
.Select(x => x.OrderByDescending(y => y.FileName.Split(new char[] { '_' })[2]).First())
.OrderBy(x => x.FileName.Split(new char[] { '_' })[1]);
foreach (FtpFileInfo order in orders) {
Console.WriteLine(order.FileName);
}
The output I receive is shown below which matches what you mentioned was the desired output.
XXX_AE_V3_20161012152126.xml
XXX_AU_V4_20190513142439.xml
XXX_BR_V6_20171048214049.xml
Upvotes: 2
Reputation: 38598
You could try to use Select
scope to define it as a result, but use the scope to avoid calling Slipt
for each property (performance). Use OrderBy
and ThenBy
and you will get ordered as you want. Finally, use ToList
method to get it in a better structure (list of anon objects) when a generic one.
var res = xmlFileNames.Select(s =>
{
var a = s.Split('_');
return new
{
XXX = a[0],
Country = a[1],
Version = a[2],
FileDate = a[3]
};
})
.OrderByDescending(x => x.Version)
.ThenBy(x => x.Country)
.ToList();
Upvotes: 0