【问题标题】:How to order list in custom Item class with linq query如何使用 linq 查询在自定义项目类中排序列表
【发布时间】:2019-09-13 15:13:38
【问题描述】:

我有两门课

class Variant
{
    bool isOrdered;
}
class Item
{
    List<Variant> Variants;
}

然后我从我的数据源获得IQueryable&lt;Item&gt;。我想订购变体列表。
例如,如果执行查询 IQueryable&lt;Item&gt; 我们得到:

{Item: Variants:{true,false,true}, Item: Variants:{false, false, true}, Item: Variants:{true,false,true,false}}

订购后我需要获取

{项目:变体:{true,true, false},项目:变体:{true,true,false},项目:变体:{true,true,false,false}}

我正在尝试类似的东西

var query =
        from item in source
        from variants in item.Variants
        orderby variants.isOrdered
        select item;

但是这个查询不是订购变体,而是订购物品,我不知道如何订购变体。

【问题讨论】:

  • 您想只订购变体还是同时订购商品?如果还有商品,订购标准是什么?
  • 只有变体。 (评论的长度必须至少为 15 个字符。)
  • 您只对选择变体感兴趣,对吧?还是你也需要这些物品?
  • 我也需要选择item 而且in item可以是多个字段)。
  • 这会改变上下文。您是否需要以特定方式订购的物品? Variant的源代码可以修改或添加吗?

标签: c# linq


【解决方案1】:

如果你感兴趣的只是变种,你可以试试:

var selections = source.Select(i => i.Variants.OrderByDescending(v => v.isOrdered));

selections 将成为一个IEnumerable&lt;IOrderedEnumerable&lt;Variant&gt;&gt;,其中包含三个变量枚举(基于您的样本数据),按以下方式排序:

对,对,错

真假假

真,真,假,假

更新:

OP 已更新问题以要求该项目,所以...

有几种方法可以解决这个问题。最少基于 OOP、最少干扰的方法是将项目以及已排序的变体列表抓取到匿名类型中:

var selections = source.Select(i => new 
{ 
    Item = i, 
    SortedVariants = i.Variants.OrderByDescending(v => v.isOrdered)
});

在这种情况下,selections 将是一个IEnumerable&lt;'a&gt;,其中'a 是匿名类型。该类型将具有两个属性:变体所属的项目以及名为SortedVariants 的属性。

然后有最简单的,不可重复使用的方法。每次访问变体时,对它们进行排序:

foreach (var item in source)
{
    var variants = item.Variants.OrderByDescending(v => v.isOrdered);          
    //Do something with the variants
}

一种更可重用的方法是向Variant 类添加另一个属性(或方法),该类以所需的顺序返回变体列表:

public class Item
{   
    public List<Variant> Variants;

    public IOrderedEnumerable<Variant> OrderedVariants
    {
        get { return Variants.OrderByDescending(v => v.isOrdered); }
    }

    //OR

    public IOrderedEnumerable<Variant> GetOrderedVariants()
    {
        return Variants.OrderByDescending(v => v.isOrdered);
    }
}

然后您可以改用该属性或方法。

最后,如果您可以灵活地更改当前的设计,您可以随时将列表隐藏在接口后面并实现添加方法:

public class Item
{   
    private List<Variant> _variants = new List<Variant>();
    public IEnumerable<Variant> Variants
    {
        get { return _variants.OrderByDescending(v => v.isOrdered); }            
    }

    public void AddVariant(Variant variant)
    {
        _variants.Add(variant);
    }
}

这是我个人最喜欢的,因为它提供了变体、满足要求并隐藏了实现的细节。

【讨论】:

    【解决方案2】:

    如果您只想对 Variant 进行排序,请执行以下操作:

    var SortedVariantItems= Items.Select(x =>new Item {Variants= x.Variants.OrderByDescending(c => c.isOrdered).ToList()})
    

    如果你想除了 Variant,项目也可以排序(按 Variant),这样做:

    var SortedItems= Items.Select(x =>new Item {Variants= x.Variants.OrderByDescending(c => c.isOrdered).ToList()}).OrderByDescending(x=>x.Variants.Count(c=>c.isOrdered));
    

    【讨论】:

    • 为了对内部属性进行排序而创建新项目对我来说似乎不是一个好主意。
    • 根据问题“... and after ordering I need to get {Item: Variants:{true,true, false}, Item: Variants:{true,true,false}, Item: Variants:{true,true,false,false}} ”我们也想要物品。但是您只返回变体。如果项目有其他字段怎么办?
    • 是的,你的解决方案是可行的,但在我的项目中 Item 有超过 30 个字段,并且会随着时间而变化。你知道我该如何处理它吗?
    • 是的,我有想法。如果您不想每次都创建新项目,则必须使用 IComparable 接口。您知道如何使用它吗?请参阅link。如果您有任何问题,我可以帮助您。我希望它有帮助
    【解决方案3】:

    我建议如下。

    var orderedItems = Items.OrderBy(item => item.Variants.Where(v => v.isOrdered).Count());
    

    这会根据订购的变体数量对项目进行排序。你可以在哪里替换任何你喜欢的东西。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-25
      • 2020-11-29
      相关资源
      最近更新 更多