将有多个匹配项的项目移动到列表顶部

时间:2016-02-28 16:21:05

标签: c#

我有一个列表,其中可以包含多个人的记录:

 result =people.Select(p => new PersonDetail
            {
                Involvement =  p._Discriminator,
                FullName = p.BuildFullName(),
                DateOfBirth = p.DateOfBirth != null ? p.DateOfBirth.Value.ToShortDateString() : string.Empty,
                Race = MappingExtensions.MergeCodeAndText(p.RaceCode, p.RaceText),
                Sex = MappingExtensions.MergeCodeAndText(p.SexCode, p.SexText),
                Height = p.Height,
                Weight = p.Weight != null ? p.Weight.ToString() : string.Empty,
                EyeColor = MappingExtensions.MergeCodeAndText(p.EyeColorCode, p.EyeColorText),
                HairColor = MappingExtensions.MergeCodeAndText(p.HairColor1Code, p.HairColor1Text),
                //...
            }).ToList();

我想按参与类型(受害者,嫌疑人,证人)订购此列表。

我已使用RemoveInsert

尝试了以下操作
foreach (var i in result.Where(i => i.Involvement.ToLower() =="suspect"))
            {
                result.Remove(i);
                result.Insert(0, i);
            }
            return result;

在第一个循环上它按预期工作,但是在第二个循环中我得到一个异常抛出。我怀疑有一些递归或抛出异常,因为它一直找到我在第一次通过时提升的记录并且无法通过它。

我想执行循环而不是一次传递,因为可能有多个记录被标记为可疑。我需要将所有这些提升到证人或受害者之上。其他参与与订购无关。

示例:

Bob "suspect"
Jane"suspect"
Kenny "witness"
Joe "victim"

有关如何选择多条记录并确保它们位于列表顶部而不是其他记录的任何建议吗?

感谢您的任何想法或建议

2 个答案:

答案 0 :(得分:1)

首先,您无法在foreach中更改结果集合。 foreach中使用的集合是不可变的,这里是带有解释的MSDN链接:foreach

您可以使用OrderBy重新排序您的收藏:

    result = result.OrderBy(r => r.Involvement.ToLower() =="suspect" ? 0 : 1).ToList();

OrderBy中的表达将促进"怀疑"项目位于结果的顶部。

答案 1 :(得分:1)

如果订购的列表仅关注Suspect位于列表顶部的优先级,即

,则目前接受的答案才会成功。
Kenny, Witness
Bob, Suspect
Joe, Victim
Jane, Suspect

换句话说,如果排序优先顺序还包括WitnessVictim,则接受的答案将是正确的,因为Witness已经优先于受害者的顺序;使用接受的答案时,结果将正确:

Bob, Suspect
Jane, Suspect
Kenny, Witness
Joe, Victim

但是,如果排序优先顺序必须包含" Suspect"以外的字符串,则接受的答案将失败,即如果列表以“,

列出来”
Jill, Victim
Kenny, Witness
Bob, Suspect
Joe, Victim
Jane, Suspect

然后结果将是:

Bob, Suspect
Jane, Suspect
Jill, Victim
Kenny, Witness
Joe, Victim

但是,正确的结果应该是(假设Witness优先于受害者):

Bob, Suspect
Jane, Suspect
Kenny, Witness
Jill, Victim
Joe, Victim

要根据非alpha排序进行自定义排序,您需要提供某种类型的IComparer或类似内容:

// Sample class with a name and involvement:
public class Detail
{
    public string Name { get; set; }
    public string Involvement { get; set; }

    public Detail( string name, string involvement )
    {
        Name = name;
        Involvement = involvement;
    }
}

// implementation of IComparer that uses a custom alpha sort:
public class DetailComparer : IComparer<Detail>
{
    static readonly List<string> Ordered = new List<string> { "suspect", "witness", "victim" };
    public int Compare( Detail x, Detail y )
    {
        int i = Ordered.FindIndex( str => str.Equals( x.Involvement, StringComparison.OrdinalIgnoreCase ) );
        int j = Ordered.FindIndex( str => str.Equals( y.Involvement, StringComparison.OrdinalIgnoreCase ) );

        if( i > j ) return 1;
        if( i < j ) return -1;
        return 0;
    }
}

然后可以通过提供比较器对列表进行排序:

var details = new List<Detail>
{
    new Detail("Jill", "Victim"),
    new Detail("Kenny", "Witness"),
    new Detail("Bob", "Suspect"),
    new Detail("Joe", "Victim"),
    new Detail("Jane", "Suspect"),
};

details.Sort( new DetailComparer() );

通过提供自定义IComparer,可以为每个&#34; Involvement&#34;声明任何优先级。