获取List中的不同值列表

250

在C#中,假设我有一个名为Note的类,该类有三个字符串成员变量。

public class Note
{
    public string Title;
    public string Author;
    public string Text;
}

我有一个类型为Note的列表:

List<Note> Notes = new List<Note>();

如何获取“Author”列中所有不同值的干净方法?

我可以遍历列表并将所有非重复值添加到另一个字符串列表中,但这似乎很低效。 我有一种感觉,有一些神奇的Linq构造可以在一行中完成此操作,但我还没有想出任何方法。

6个回答

462
Notes.Select(x => x.Author).Distinct();

这将返回一个序列 (IEnumerable<string>),其中每个唯一值都对应一个 Author 值。


3
Notes.Select(x => x.Author).AsParallel().Distinct(); 如果我们不关心顺序并且列表中有更多项,那么使用"AsParallel()"可能会带来一些性能优势。该代码的作用是选择所有笔记的作者并去除重复项。 - Sai
1
@Kiquenet,使用“Default”相等比较器进行不同处理。https://msdn.microsoft.com/zh-cn/library/bb348436(v=vs.110).aspx - Georg Patscheider
6
如果你想要转换为列表,那么在Distinct()之后而不是之前。例如:Notes.Select(x => x.Author).Distinct().ToList(); - MTwiford
@KirkWoll 如何“将结果投射回具有作者属性的匿名类型中”?Dan Busha的答案需要我添加一个库;不想添加任何库。抱歉,我不习惯这种Linq和Fluent API语法。请帮忙,谢谢。 - Abubakar Riaz
@KirkWoll 我一直在尝试实现这个 https://stackoverflow.com/questions/64798230/distinct-column-in-selectlist-for-dropdown-list。但我总是很困难。不过现在问题已经得到解决,而且方法非常简单。非常感谢您指出“匿名类型添加”技巧。 - Abubakar Riaz
显示剩余5条评论

131

按作者区分Note类

var DistinctItems = Notes.GroupBy(x => x.Author).Select(y => y.First());

foreach(var item in DistinctItems)
{
    //Add to other List
}

1
难道不应该是 Notes,就像在 Notes.GroupBy() 中使用复数的 s 一样,因为 Note 只能保存一个单独的笔记吗? - kkuilla

47

Jon Skeet编写了一个名为morelinq的库,其中包含一个DistinctBy()操作符。请参见此处以获取实现方式。你的代码将类似于:

IEnumerable<Note> distinctNotes = Notes.DistinctBy(note => note.Author);

更新: 如果您只是想寻找一个不同的作者集合,Kirk 给出了正确的答案。

添加了示例,DistinctBy 中有几个字段:

res = res.DistinctBy(i => i.Name).DistinctBy(i => i.ProductId).ToList();

非常好,谢谢。我喜欢在调用Distinct方法之前对列表进行排序,它可以保持正确的顺序。 - Vilhelm
我更新了链接。MoreLINQ现在在Github上,并且可以通过Nuget安装:Install-Package morelinq - Chad Levy

3
public class KeyNote
{
    public long KeyNoteId { get; set; }
    public long CourseId { get; set; }
    public string CourseName { get; set; }
    public string Note { get; set; }
    public DateTime CreatedDate { get; set; }
}

public List<KeyNote> KeyNotes { get; set; }
public List<RefCourse> GetCourses { get; set; }    

List<RefCourse> courses = KeyNotes.Select(x => new RefCourse { CourseId = x.CourseId, Name = x.CourseName }).Distinct().ToList();

通过使用上述逻辑,我们可以获得唯一的课程。

你的Distinct在ToList之前让我省了时间。我在ToList之后进行操作,但是出现了无法将列表转换为IEnumerable的错误。 - Ajay2707
3
Distinct在这里不起作用,因为对于此运算符,每个对象都基于对象的哈希码是唯一的。你需要类似于这个的东西 - https://github.com/morelinq/MoreLINQ/blob/master/MoreLinq/DistinctBy.cs - Bose_geek

-1

@if (dataModal.Count > 0)
{
    var DistinctItems = dataModal.GroupBy(x => x.Year).Select(y => y.First());

    <div class="col-md-3">
        <label class="fs-7 form-label text-muted">@Localizer["Year"]</label>
            <InputSelect id="ddlYears" class="form-select" @bind-Value="filter.Year">                            
                <option value="">@Localizer["Select"]</option>
                @foreach (var year in DistinctItems)
                {
                   <option value="@year.Year">
                       @year.Year
                   </option>
                }
            </InputSelect>
    </div>
}


这与问题有什么关系?请始终添加解释,而不仅仅是代码。 - Gert Arnold
如果只是关于第二行代码,那么这只是重复了一个已有的答案,但使用您自己的对象,并没有真正帮助到您。 - Gert Arnold

-3
mcilist = (from mci in mcilist select mci).Distinct().ToList();

MCI 到底是什么?只是一个示例表格吗?答案有点尴尬。 - Brad Koch
1
是的,我认为这并不符合我的原始问题(算了吧,那已经是一年半以前的事情了,而且项目早已完成)。据我所知,如果我已经有一个包含重复项的作者字符串列表,那么这将起作用,但不能用于从具有作者字符串作为其字段之一的对象列表中提取这样的列表。 - Darrel Hoffman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接