【问题标题】:LINQ - order by another collection [closed]LINQ - 按另一个集合排序[关闭]
【发布时间】:2018-08-10 16:01:45
【问题描述】:

我有一个元素集合:

public class CompanyVistracksDomain
{
    public int ID { get; set; }
    public string Name { get; set; }
    public int VistracksAccountId { get; set; }
}    

还有另一个元素集合:

public class VistrackAccountInfoDomain
{
    public int Id { get; set; }
    public string Name { get; set; }                
}

所以,我有:

List<CompanyVistracksDomain> companies =
    await _companyService.CompanyListHasVistracksIdAsync();

List<VistrackAccountInfoDomain> accList =
    await _vistracksService.GetAllAccountsAsync(companies);

它们有相似的元素列表。 第一个序列包含出现在第二个序列中的所有元素。第一个集合已排序。如何像第一顺序一样对第二个集合进行排序?

【问题讨论】:

  • 如果第二个列表可能包含第一个列表中不存在的元素,那么对第一个列表进行 like 排序意味着什么?你会如何调和它们?
  • 将您的DriverVistacksInfoElement 类添加到代码示例中
  • “第一个集合已排序”,我没有看到任何排序。那你为什么不应用相同的排序逻辑呢?
  • @Franck,搞错了,我修好了
  • @CamiloTerevinto,为什么你需要知道它是如何排序的?在CompanyListHasVistracksIdAsync内部按特定逻辑排序,不能在GetAllAccountsAsync中应用

标签: c# linq sorting collections


【解决方案1】:
using System.Linq;

IEnumerable<CompanyVistracksDomain> companies = new List<CompanyVistracksDomain>();
IEnumerable<VistrackAccountInfoDomain> accList = new List<VistrackAccountInfoDomain>();

companies = companies.OrderBy(o => o.Name );
accList = accList.OrderBy(o => o.Name );

【讨论】:

    【解决方案2】:

    OP 的注释表明第二个集合是第一个集合的正确子集。在这种情况下,您可以简单地将第一个集合与第二个集合相交。这将有效地返回第二个集合的元素,但按照它们出现在第一个集合中的顺序:

    List<CompanyVistracksDomain> companies =
        await _companyService.CompanyListHasVistracksIdAsync();
    
    
    List<VistrackAccountInfoDomain> accList =
        await _vistracksService.GetAllAccountsAsync(companies);
    
    List<VistrackAccountInfoDomain> sorted = 
        companies.Intersect(accList);
    

    如果VistrackAccountInfoDomain 不是从CompanyVistrackDomain 派生的,那么您将不得不手动模仿Intersect 行为:

    public IEnumerable<VistrackAccountInfoDomain> Intersect(
        CompanyVistracksDomain first,
        VistrackAccountInfoDomain second)
    {
        Set<int> set = new Set<int>();
        Dictionary<int, VistrackAccountInfoDomain> content = 
            new Dictionary<int, VistrackAccountInfoDomain>();
    
        foreach (TSource element in second)
        {
            set.Add(element);
            content[element.Id] = element;
        }
    
        foreach (TSource element in first)
            if (set.Remove(element.Id)) 
                yield return content[element.Id];    
    }
    

    这个实现假设至少有一些方法可以匹配两个序列的元素,例如一些Id属性。

    【讨论】:

    • Intersect 函数是否接受不同类型的集合?
    • @Fabio 刚刚添加了两种类型不相关但有识别相同对象的Id字段时的实现。
    【解决方案3】:

    假设他们的 ID 对于每个条目都是唯一的,您可以试试这个:

    var indices = companies
        .Select((item, index) => new { item, index })
        .ToDictionary(x => x.item.ID, x => x.index);
    var result = accList
        .OrderBy(x => indices[x.Id])
        .ToList();
    

    编辑:优化了一点

    【讨论】:

    • 哇...这个解决方案的复杂度最多为 'O(N^2)',并且知道 OrderBy 已延迟执行,总时间复杂度可能为 O(N^3 log N) .你真的不知道吗? 100 个元素将运行一秒钟。 1000 个元素将永远不会返回。
    • @ZoranHorvat,我虽然是这样,但似乎它是 O(N+1)...一旦执行公司。Select(...) 然后 orderby...
    猜你喜欢
    • 2015-10-18
    • 1970-01-01
    • 1970-01-01
    • 2015-07-21
    • 1970-01-01
    • 2016-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多