簡體   English   中英

C#LINQ GroupBy與where條件

[英]C# LINQ GroupBy with where condition

你知道什么是最簡單有效的方法來獲得一個列表'在哪里'+有一個元素列表不符合那些條件?

再具體一點:

這是我工作的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時這種方式是否正確?

首先要注意的是:請使用System.IO.Path方法。 他們會讓生活變得更加輕松。 您可以使用Path.GetFileNameWithoutExtension獲取不帶擴展名的文件名,也可以通過Path.GetExtension獲取擴展名。 這使您更容易理解您在做什么。

其次,問題是您要丟棄所有沒有擴展名的文件。 您可以避免這種情況,只需分配一個空的分機,如果分機不符合您的預期范圍,並為此分配最低優先級。 這基本上交換你where與其他第一次嘗試select是重置擴展到null ,如果不支持擴展。

第三,至少當您的擴展列表沒有動態變化時,您也可以使用常規List 這比SortedList具有更小的開銷。

我建議像這樣:

  //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屬性(如果文件有支持的擴展名)。 我們可以在匿名類的幫助下完成此操作:

  var filesList = Directory
    .EnumerateFiles(Path.Combine(Directory.GetCurrentDirectory(), "images"))
    .Select(file => {
       string extension = Path.GetExtension(file);      
       int extIndex;
       bool wanted = supportedExtensions.TryGetValue(extension, out extIndex);       

       return new {
         name = file,
         title = Path.GetFileNameWithoutExtension(file),
         extension = extension,
         extIndex = wanted ? extIndex : -1,
         wanted = wanted, }; })
    .Where(item => item.wanted) // you may want to comment out this condition
    .GroupBy(item => item.title)  
    .Select(group => group
       .OrderBy(item => item.extIndex)
       .First()
       .name);

您可以使用.Except從IEnumerable中刪除項目,因此生成與您的條件不匹配的項目。

List<string> all = AllFiles();

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

我會這樣做:

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();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM