C#LINQ GroupBy with where condition

时间:2017-06-22 06:21:27

标签: c# linq validation

你是否知道在某些'where'之后获取列表的最简单有效的方法是什么?+有一个不符合条件的元素列表?

具体来说:

这是我工作的linq。它获取fileNames,将其拆分为名称和扩展名元组列表,并且: - 名称应该是唯一的 - 扩展是基于排序列表(所以首先是gif,如果没有这个名称的gif取png,那么jpg然后是jpeg,不支持任何其他扩展名)

/// <summary>
/// Supported image extensions.
/// The list is sorted cause we have priorities here.
/// </summary>
SortedList<short, string> supportedExtensions = new SortedList<short, string> { { 1, "gif" }, { 2, "png" }, { 0, "jpg" }, { 4, "jpeg" } };


var filesList = Directory.GetFiles(string.Concat(Directory.GetCurrentDirectory(), "\\images", "\\"))
                            .Select(s => Tuple.Create(s.Substring(s.LastIndexOf(@"\") + 1, s.LastIndexOf(@".") - 1 - s.LastIndexOf(@"\")), s.Substring(s.LastIndexOf(@".") + 1)))
                            .Where(x => supportedExtensions.Values.Contains(x.Item2)) // only supported extensions here!
                            .GroupBy(g => g.Item1) // we are assured that every group has proper and at least one value
                            .Select(group => group.OrderBy(o => supportedExtensions.IndexOfValue(o.Item2)).First()); // get only one extension in each name group by priorities as in sorted list

线索是我还想要不符合条件的filesList,以便在警告信息中写下这些文件名(然后就可以忘记了)。

我试图用这种方式做到这一点:

var fileListGroupedBySupportedExtension = Directory.GetFiles(Directory.GetFiles(string.Concat(Directory.GetCurrentDirectory(), "\\images", "\\")))
                            .Select(s => Tuple.Create(s.Substring(s.LastIndexOf(@"\") + 1, s.LastIndexOf(@".") - 1 - s.LastIndexOf(@"\")), s.Substring(s.LastIndexOf(@".") + 1)))
                            .GroupBy(g => supportedExtensions.Values.Contains(g.Item2));

var fileListWithSupportedExtension = fileListGroupedBySupportedExtension
                                .Where(gr => gr.Key == true);

但是我不知道如何进入这个列表并在另一个地方选择或选择所以我显然做错了什么:)

处理此类验证/ linq时这种方式是否正确?

4 个答案:

答案 0 :(得分:1)

首先要注意的是:请使用System.IO.Path方法。他们会让生活变得更加轻松。您可以使用Path.GetFileNameWithoutExtension获取不带扩展名的文件名,也可以通过Path.GetExtension获取扩展名。这使您更容易理解您在做什么。

其次,问题是您要丢弃所有没有扩展名的文件。您可以避免这种情况,只需分配一个空的分机,如果分机不符合您的预期范围,并为此分配最低优先级。这基本上会在第一次尝试中将您的where与另一个select进行交换,如果扩展程序不受支持,则会将扩展名重置为null

第三,至少当您的扩展程序列表没有动态更改时,您也可以使用常规List。这比SortedList的开销小。

答案 1 :(得分:1)

我建议这样的事情:

Connection.readonly(name)

编辑:让我们只计算一次 //DONE: You're trying to use Sorted List as a Dictionary Dictionary<string, int> supportedExtensions = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase) { {".gif", 1}, {".png", 2}, {".jpg", 0}, {".jpeg", 4}, }; //DONE: Enumerate - do not retrieve all the files and then continue working //DONE: Do no reinvent the wheel - Path class var filesList = Directory .EnumerateFiles(Path.Combine(Directory.GetCurrentDirectory(), "images")) .Where(file => supportedExtensions.ContainsKey(Path.GetExtension(file))) .GroupBy(file => Path.GetFileNameWithoutExtension(file)) .Select(group => group .OrderBy(o => supportedExtensions[o]) .First()); //.ToArray(); // <- if you want the final materialization (不是非常有用的优化);并让我们选择Path.GetExtension属性(如果文件具有受支持的扩展名)。我们可以在匿名类的帮助下完成此任务:

wanted

答案 2 :(得分:1)

您可以使用enter image description here从IEnumerable中删除项目,因此生成与您的条件不符的项目。

List<string> all = AllFiles();

IEnumerable<string> matching    = all.Where(f => Condition(f));
IEnumerable<string> notMatching = all.Except(matching);

答案 3 :(得分:0)

我会这样做:

List<string> supportedExtensions = new List<string> {".jpg", ".gif", ".png", ".jpeg"};// Supported extensions in valid order

var filesList = Directory.GetFiles(Path.Combine(Directory.GetCurrentDirectory(), "\\images")).Select(x => x.ToLower()).ToList(); // Get all files from directory
var filesWithoutSupportedExtensions = filesList.Where(x => !supportedExtensions.Contains(Path.GetExtension(x))).ToList(); // Get files that do not have supported extension
var filesWithSupportedExtensions = filesList.Where(x => supportedExtensions.Contains(Path.GetExtension(x))).ToList(); // Get files with supported extension
var firstFilesWithUniqueName = filesWithSupportedExtensions.GroupBy(x => Path.Combine(Path.GetDirectoryName(x), Path.GetFileNameWithoutExtension(x)))
    .Select(g => g.OrderBy(f => supportedExtensions.IndexOf(Path.GetExtension(f))).First()).ToList(); // Get file with unique name that has first extension from list
var otherFiles = filesWithSupportedExtensions.Except(firstFilesWithUniqueName).ToList(); // Get all other files

Console.WriteLine(string.Join(Environment.NewLine, firstFilesWithUniqueName));
Console.WriteLine("Files without supported extensions:");
Console.WriteLine(string.Join(Environment.NewLine, filesWithoutSupportedExtensions));

Console.WriteLine("Files with duplicated name and different extension:");
Console.WriteLine(string.Join(Environment.NewLine, otherFiles));
Console.ReadKey();