JAZ
JAZ

Reputation: 1070

Filtering List Objects Based on Property String

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

Answers (3)

Tyddlywink
Tyddlywink

Reputation: 891

I left FtpFileType out because I didn't know what a valid value is but this should do it for ya.

c#Fiddle

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

ivcubr
ivcubr

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

Felipe Oriani
Felipe Oriani

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

Related Questions