如何在C#中使用带有条件的selectmany

时间:2019-04-30 10:14:54

标签: c# json linq lambda

我有文件搜索库,文件详细信息存储在以下结构的CosmosDB中

{​
  "id": "e7f56bbc-3387-4034-9eab-03cdaaa7bead",​
  "fileName": "reviewforq1",​
  "parentId": "",​
  "year": 2019,​
  "quarter": "q1",​
  "path": "<>",​
  "content": [​
    {​
      "version": 1,​
      "state": "submitted",​
      "createdBy": "person1",​
      "createdOn": "10/04/2019 15:16:00",​
      "data": [​
        {​
          "field": "scheme",​
          "value": "abc",​
          "isColorEnabled": "false",​
          "color": "",​
          "isFlagEnabled": "false",​
          "flags": [],​
          "isCommentsEnabled": "false",​
          "comments": ""​
        },​
        {​
          "field": "projectNumber",​
          "value": "abc123",​
          "isColorEnabled": "false",​
          "color": "",​
          "isFlagEnabled": "false",​
          "flags": [],​
          "isCommentsEnabled": "false",​
          "comments": ""​
        }
    }
}

我在库中使用下面的模型

public class Files
{
    [JsonProperty(PropertyName = "id")]
    public Guid Id { get; set; }
    [JsonProperty(PropertyName = "fileName")]
    public string FileName { get; set; }
    [JsonProperty(PropertyName = "parentId")]
    public Guid ParentId { get; set; }
    [JsonProperty(PropertyName = "year")]
    public int Year { get; set; }
    [JsonProperty(PropertyName = "quarter")]
    public string Quarter { get; set; }
    [JsonProperty(PropertyName = "path")]
    public string Path { get; set; }
    [JsonProperty(PropertyName = "content")]
    public List<Content> Content { get; set; }
}
public class FileVersionDetails
{
    public Guid Id { get; set; }
    public string Path { get; set; }
    public string Quarter { get; set; }
    public int Year { get; set; }
    public string FileName { get; set; }
    public List<Data> Data { get; set; }
    public string CreatedBy { get; set; }
    public DateTime CreatedOn { get; set; }
    public int Version { get; set; }
}

这是我搜索文件集合以获取文件最新版本的方式。

List<FileVersionDetails> latestFileVersionDetails = new List<FileVersionDetails>();
var fileVersionDetails = files
.SelectMany(j => j.Content,
    (parent, child) => new FileVersionDetails
    {
        Id = parent.Id,
        Path = parent.Path,
        Quarter = parent.Quarter,
        Year = parent.Year,
        FileName = parent.FileName,
        Data = child.Data,
        CreatedBy = child.CreatedBy,
        CreatedOn = child.CreatedOn,
        Version = child.Version
    });

var fileIds = files.Select(i => i.Id);

foreach (var item in fileIds)
{
    var fileVersions = fileVersionDetails.Where(k => k.Id == item);
    int maxVersion = fileVersions.Max(l => l.Version);

    latestFileVersionDetails.Add(fileVersions.Where(o => o.Version == maxVersion).FirstOrDefault());
}

这行得通,但是我认为应该有一种有效的方法来完成此任务而无需foreach,如果我以错误的方式使用了它,或者可以做任何改进,请提出建议。

谢谢

2 个答案:

答案 0 :(得分:1)

您可以按fileVersionDetailsId进行分组,并按Version对每个组进行排序:

var fileVersionDetails = ...;

List<FileVersionDetails> latestFileVersionDetails = fileVersionDetails
    .GroupBy(x => x.Id)
    .Select(g => g.OrderByDescending(g => g.Version).First())
    .ToList();

或者:

List<FileVersionDetails> latestFileVersionDetails = files
    .SelectMany(...)
    .GroupBy(x => x.Id)
    .Select(g => g.OrderByDescending(g => g.Version).FirstOrDefault())
    .ToList();

答案 1 :(得分:1)

您可以添加LINQ扩展方法MaxBy(或从MoreLinq获取)以找到每个文件Id的最大值:

public class IEnumerableExt {
    public static T MaxBy<T, TKey>(this IEnumerable<T> src, Func<T, TKey> keySelector) => src.Aggregate((a, b) => Comparer<TKey>.Default.Compare(keySelector(a), keySelector(b)) >= 0 ? a : b);
}

使用扩展名,您只需找到每个Id的最大fileVersionDetails:

var latestFileVersionDetails = fileVersionDetails
                                    .GroupBy(f => f.Id)
                                    .Select(fg => fg.MaxBy(f => f.Version))
                                    .ToList();