微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

LINQ:防止创建新对象,如果对象存在,则追加到列表属性

如何解决LINQ:防止创建新对象,如果对象存在,则追加到列表属性

(我是C#的初学者) 我想使用2个列表(用户列表和帖子列表)创建Person类的列表,这里是类结构的外观。问题:在使用LINQ创建对象时,我希望不创建同一个人对象(即,具有相同名称,userId,Id)。使用LINQ甚至可能吗? (我正在使用System.linq)

class User
{
    public string Id                { get; set; }
    public string Name              { get; set; }
}

class Post
{
    public string Id                { get; set; }
    public string UserId            { get; set; }
    public string Text              { get; set; }
}
class Person
{
    public string Name              { get; set; }
    public string Id                { get; set; }
    public string UserId            { get; set; }
    public List<string> listofPosts { get; set; }
    public Person(string Id,string Name,string UserId)
    {
        this.Name = Name;
        this.Id = Id;
        this.UserId = Id;
    }
}

class Test
{
    static void Main()
    {
        
        List<User> userList = UserRepository.GetUsers(); // sample data
        List<Post> postList = PostRepository.GetPosts(); // sample data
      /*
        * i want to create List of Person where person will contain UserId,ID,* name,listofPost(list<string> - containg all the post of user)
        * this is the code is wrote for creating new person,but how will i populate 
        *    person's listofPost ? 
        *    what changes do i need to make in person class ? 
        *    what changes should i do so that same person object is not created (same userId,Id,name) and contins List of post?
        *
        * one approach what i thought is - to remove duplicates by merging objects using loops.
        *    can i do this using LINQ ? 
        *    Or Is it even possible ? 
        *    
        */
        List<Person> personList = (from u in userList
                                    from p in postList
                                    where u.Id == p.UserId
                                    select (new Person(u.Id,u.Name,p.UserId))
                                    ).ToList<Person>();   
              // if i go by this logic then this creates duplicate objects ( same name,id,UserId,but with diff text ),// ( after modifying constructor and passing p.Text )
    }
}

我尝试编写逻辑,将其进行谷歌搜索,查看其他stackOverflow问题,但无法找到/理解如何解决此问题。 我是C#的初学者,还不到(经验丰富的20天)。

解决方法

您的Linq查询可以简化。我从您的描述中得到的是,您想要加载所有User,将它们选择到Person中,然后将所有Post对象添加到其中。

请考虑以下内容:

var persons = users.Select(u => 
{
   var person = new Person(u.Name,u.Id);
   person.Posts = posts.Where(p => p.UserId == u.Id).ToList();
   return person;
}).ToList();

首先,我假设您不需要p.UserId Ctor中的Person,因为它与u.Id相同。

我的发言的第二项内容是遍历所有用户,并从中找出人。在此期间,我加载了所有具有匹配Post的{​​{1}}对象,并将它们分配给“帖子列表”。

,

您可以使用group语句

List<Person> personList = (from u in userList
                           from grp in from p in postList
                                       group p by p.UserId
                           where u.Id == grp.Key
                           select new Person(u.Id,u.Name,grp.Key)
                           {
                               listOfPosts = grp.Select(x => x.Text).ToList()
                           }).ToList<Person>();

grp(由UserId分组)包含该用户的帖子列表,您可以将其查询为IEnumerable 在MSDN

中有更多相关信息

或者您可以对Person构造函数进行以下更改,并将grp作为第四个参数传递:

 public Person(string Id,string Name,string UserId,IEnumerable<Post> posts)
 {
     this.Name = Name;
     this.Id = Id;
     this.UserId = Id;
     this.listOfPosts = posts.Select(p => p.Text).ToList();
 }
,

因此,您有一个Users序列和一个Posts序列。每个User都具有零个或多个Posts,每个Post就是正好一个User的Post,即外键UserId所指的用户。一个直接的一对多关系。

实际上,可以使用LINQ来获取“带有帖子的用户”。您可以将一个“用户”中的每个“用户”转换为“用户”的所有帖子,并将其放入属性ListOfPosts中。

还有改进的空间

首先有一些建议:

此外:您的人员有一个Id和一个UserId。有什么不同?不是此人创建的用户的ID?

如果创建要由LINQ语句填充的类,通常(仅)使该类成为默认构造函数会很容易。

class Person
{
    public string Id { get; set; }
    public string Name{ get; set; }
    public ICollection<string> PostTexts { get; set; }
}

这样的类通常称为POCO(普通的老式c#对象):仅具有setter和getter的类,而没有添加的功能。

如果您真的无法更改,请说服项目负责人相信使用默认构造函数会更好,您可以使用它,但是请确保非默认构造函数至少构造一个正确的对象:为什么要命名,但没有帖子列表?

顺便说一句,我可以自由更改您的ListOfPosts。首先,它是一个字符串列表,而不是帖子列表,此外,它不包含帖子,而仅包含帖子的文本。建议:尽可能使用正确描述属性含义的属性名称。这种方式使用将不必查找字符串中的内容,因为它们不是字符串,所以他们知道这不是帖子。

此外:您可以定义Post[4]的值吗?您是否希望用户要求Pos [4]?建议:如果您希望用户不需要这些函数,则不要向类的调用者公开这些函数。只会使您更难以更改内部结构。

因此,如果您认为无法解释列表功能,但仍然希望列表中的所有内容(除索引之外):添加/删除/计数/枚举,请考虑创建一个ICollection<...>,这将为您提供内部拥有列表以外的其他东西的自由,例如数组,HashSet甚至是Dictionary。

回到您的问题

因此,根据给定的用户和帖子序列,您想要创建一个人序列。

只要您与一对多关系,并且想要“带有零个或多个子项目的项目”,例如“带有订单的客户”,“带有学生的学校”和“带有帖子的用户” ,请考虑使用Enumerable.GroupJoin

的重载之一

如果您要指定与“原始项目及其原始子项目”不同的结果,请使用带有参数resultSelector的重载:

IEnumerable<User> users = ...
IEnumerable<Post> posts = ...
var persons = users.GroupJoin(posts  // GroupJoin users and posts

    user => user.Id,// from every user take the Id
    post => post.UserId,// from every Post take the foreign key UserId

    // parameter resultSelector:
    // From every User,with his zero or more Posts make one Person
    (user,postsOfThisUser) => new Person
    {
        Id = user.Id,Name = user.Name,PostTexts = postsOfThisUser.Select(post => post.Text).ToList(),})

因此,即使PostTexts属性包含列表,您以后也可以自由更改它,而不必更改语句的用法。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。