【问题标题】:What is the simplest way to partition a list based on a criteria?根据标准对列表进行分区的最简单方法是什么?
【发布时间】:2018-11-21 09:01:47
【问题描述】:

假设我们有一个像这样的对象定义,

class MyObject {
    int id;
    string name;
}

我们有一个 MyObjects 列表。

List<MyObject> objectList

现在,我需要根据哪些对象具有非空名称字段,将此 objectList 划分为 2 个子列表。

因此,在操作之后,我需要有 2 个列表,objectsWithName,其中名称字段为非空,objectsWithoutName,其中名称字段为空(这是直接标准,但我更倾向于分区使用谓词分成两组)。

实现这一目标的最简单方法是什么?我可以在一次操作中做到这一点吗?允许使用 LINQ。

【问题讨论】:

  • 带有if语句的for循环最简单,LINQ在这里是开销
  • @brykneval - 是什么让您认为 Linq 是开销 - 您是否将 foreach 循环生成的 IL 与 Linq 生成的 IL 进行了比较?我想你会发现它们并没有太大的不同。

标签: c# list linq ienumerable


【解决方案1】:

两个 LINQ 语句就可以了:

var nameNotNull = objectList.Where(o => !string.IsNullOrEmpty(o.Name));
var nameNull = objectList.Where(o => string.IsNullOrEmpty(o.Name));

当然,您可以使用GroupBy,或者更高效的foreach 语句。

显示foreach 选项:

List<MyObject> nameNotNull = new List<MyObject>();
List<MyObject> nameNull = new List<MyObject>();

foreach (MyObject o in objectList)
{
    if (!string.IsNullOrEmpty(o.Name))
    {
        nameNotNull.Add(o);
    }
    else
    {
        nameNull.Add(o);
    }
}

【讨论】:

  • 我希望在一次迭代中对列表进行分区 - 所以我会使用 foreach 解决方案。
  • 这很好。 @SayanBose
【解决方案2】:
public class MyObject
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class MyObjectLists
{
    private readonly List<MyObject> _objects;

    public List<MyObject> NullNameObjects
    {
        get
        {
            return _objects.Where(x => x.Name == null).ToList();
        }
    }

    public List<MyObject> NonNullNameObjects
    {
        get
        {
            return _objects.Where(x => x.Name != null).ToList();
        }
    }

    public MyObjectLists(List<MyObject> objects)
    {
        _objects = objects ?? throw new ArgumentNullException(nameof(objects));
    }
}

使用代码:

var list = new List<MyObject>
{
    new MyObject
    {
        Id = 1,
        Name = "John"
    },

    new MyObject
    {
        Id = 2
    },

    new MyObject
    {
        Id = 3,
        Name = "Mary"
    },

    new MyObject
    {
        Id = 4
    }
};

var objects = new MyObjectLists(list);

foreach (MyObject myObject in objects.NonNullNameObjects)
{
    Console.WriteLine($"Object with Id {myObject.Id} has a non-null name");
}

foreach (MyObject myObject in objects.NullNameObjects)
{
    Console.WriteLine($"Object with Id {myObject.Id} has a null name");
}

【讨论】:

    【解决方案3】:

    我认为您正在寻找类似以下示例的内容:

    class MyObject 
    {
        int id;
        string name;
    }
    
    var objectList = new List<MyObject>();
    
    objectList.Add(new MyObject { name = "item 1" });
    objectList.Add(new MyObject { name = string.Empty });
    objectList.Add(new MyObject { name = "item 3" });
    
    var objectsWithName = objectList.Where(x => !string.IsNullOrEmpty(x.name));
    var objectsWithoutName = objectList.Except(objectsWithName);
    

    我创建了 2 个列表,其中第一个列表包含 MyObject 项目,其中 name 属性不为空,否则为第二个。

    【讨论】:

    • Except 这里太贵了。
    • 因为它会创建一个hashset来比较值,而完全不需要。
    猜你喜欢
    • 1970-01-01
    • 2010-12-26
    • 2019-08-17
    • 2011-12-02
    • 1970-01-01
    • 2010-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多