C#List<> OrderBy Alphabetical ABCABC NOT AABBCC

时间:2013-10-04 13:15:22

标签: c# linq sorting

我需要根据其中一个属性来排序对象列表。我找到了所有类型的答案,但没有按照我需要的方式订购。我试图命令的属性称为“DrawingName”。 我需要按如下方式订购清单: "411000A","411000B","411000C","411000D","411000A","411000B","411000C","411000D"

相反,我得到: "411000A","411000A","411000B","411000B","411000C","411000C","411000D","411000D"

当我使用以下代码时。

List<DrawingData> _DrawingList = new List<DrawingData>();

_DrawingList.Add(new DrawingData() { DrawingName = "411000D", DrawingQty = 1 });
_DrawingList.Add(new DrawingData() { DrawingName = "411000D", DrawingQty = 1 });
_DrawingList.Add(new DrawingData() { DrawingName = "411000A", DrawingQty = 1 });
_DrawingList.Add(new DrawingData() { DrawingName = "411000A", DrawingQty = 1 });        
_DrawingList.Add(new DrawingData() { DrawingName = "411000C", DrawingQty = 1 });
_DrawingList.Add(new DrawingData() { DrawingName = "411000C", DrawingQty = 1 });
_DrawingList.Add(new DrawingData() { DrawingName = "411000B", DrawingQty = 1 });
_DrawingList.Add(new DrawingData() { DrawingName = "411000B", DrawingQty = 1 });

_DrawingList.OrderBy(dn => dn.DrawingName);

var _DrawingListInOrder = _DrawingList.OrderBy(dwg => dwg.DrawingName);

8 个答案:

答案 0 :(得分:3)

到目前为止,执行一次并计算每个DrawingName的出现次数:

411000D 0x
411000D 1x
411000A 0x
411000A 1x
411000C 0x
411000C 1x
411000D 2x
411000B 0x
411000B 1x

然后您可以按事件按字母顺序对它们进行排序。

411000A 0x
411000B 0x
411000C 0x
411000D 0x
411000A 1x
411000B 1x
411000C 1x
411000D 1x
411000D 2x

答案 1 :(得分:2)

不是说这是最有效的方法,但它有效:

List<DrawingData> _DrawingList = new List<DrawingData>();

_DrawingList.Add(new DrawingData() { DrawingName = "411000D", DrawingQty = 1 });
_DrawingList.Add(new DrawingData() { DrawingName = "411000D", DrawingQty = 1 });
_DrawingList.Add(new DrawingData() { DrawingName = "411000A", DrawingQty = 1 });
_DrawingList.Add(new DrawingData() { DrawingName = "411000A", DrawingQty = 1 });
_DrawingList.Add(new DrawingData() { DrawingName = "411000C", DrawingQty = 1 });
_DrawingList.Add(new DrawingData() { DrawingName = "411000C", DrawingQty = 1 });
_DrawingList.Add(new DrawingData() { DrawingName = "411000B", DrawingQty = 1 });
_DrawingList.Add(new DrawingData() { DrawingName = "411000B", DrawingQty = 1 });

var _WithIndex = _DrawingList.Select(x => new { DrawingData = x, Index = _DrawingList.Where(y => y.DrawingName == x.DrawingName).ToList().IndexOf(x) });
var _FinalOrder = _WithIndex.OrderBy(x => x.Index).ThenBy(x => x.DrawingData.DrawingName).Select(x => x.DrawingData);

Console.WriteLine("Final Sort:");
Console.WriteLine(string.Join("\n", _FinalOrder));

Console.ReadLine();

获取每个重复项的索引,然后对该索引进行排序,然后对名称进行排序。

使它更简单一些。可以是单个LINQ语句:

var _FinalOrder = _DrawingList
    .Select(x => new
        {
            DrawingData = x,
            Index = _DrawingList.Where(y => y.DrawingName == x.DrawingName)
                                .ToList()
                                .IndexOf(x)
        })
    .OrderBy(x => x.Index)
    .ThenBy(x => x.DrawingData.DrawingName)
    .Select(x => x.DrawingData);

答案 2 :(得分:0)

假设这用于相对少量的数据,以下伪代码可能会满足您的需求:

Take the list L of things to sort
Sort L normally (AABBCCDD order)
Create an empty list L2 and an empty set S
While L still has elements:
    Iterate over L
        If current element E is in S, ignore it
        Otherwise, add E to S, add it to the end of L2 and remove it from L
    Clear S

在此之后,L2应该具有ABCDABCD顺序的元素。

答案 3 :(得分:0)

试试这个:

using System;
using System.Collections.Generic;
using System.Linq;

class DrawingData {
    public string DrawingName{get;set;} 
    public int DrawingQty {get;set;}
}

class DrawingDataComparer : IEqualityComparer<DrawingData>
{

    public bool Equals(DrawingData d1, DrawingData d2)
    {
        return d1.DrawingName.Equals(d2.DrawingName);
    }


    public int GetHashCode(DrawingData d)
    {
        return d.DrawingName.GetHashCode();
    }

}

public class Test
{
    public static void Main()
    {
        List<DrawingData> _DrawingList = new List<DrawingData>();
        _DrawingList.Add(new DrawingData() { DrawingName = "411000D", DrawingQty = 1 });
        _DrawingList.Add(new DrawingData() { DrawingName = "411000D", DrawingQty = 1 });
        _DrawingList.Add(new DrawingData() { DrawingName = "411000A", DrawingQty = 1 });
        _DrawingList.Add(new DrawingData() { DrawingName = "411000A", DrawingQty = 1 });        
        _DrawingList.Add(new DrawingData() { DrawingName = "411000C", DrawingQty = 1 });
        _DrawingList.Add(new DrawingData() { DrawingName = "411000C", DrawingQty = 1 });
        _DrawingList.Add(new DrawingData() { DrawingName = "411000B", DrawingQty = 1 });
        _DrawingList.Add(new DrawingData() { DrawingName = "411000B", DrawingQty = 1 });

        _DrawingList = _DrawingList.OrderBy(c => c.DrawingName).ToList();
        var distinct = _DrawingList.Distinct(new DrawingDataComparer());
        var organized = distinct.Concat(_DrawingList.Except(distinct));
        foreach(DrawingData dd in organized)
            Console.WriteLine(dd.DrawingName);
    }
}

答案 4 :(得分:0)

根据我对要求的理解,您需要订购每个独特的套装。因此,采取一个独特的设置,订购,并保持它。然后删除刚刚使用的那些并再次执行。继续前进,直到你没有更多独特的订单来订购。

List<DrawingData> ordered = new List<DrawingData>();
while (_DrawingList.Any())
{
    var temp = _DrawingList.Distinct().OrderBy(dd => dd.DrawingName, StringComparer.CurrentCultureIgnoreCase);
    ordered.AddRange(temp);
    foreach (var remove in temp)
    {
        _DrawingList.Remove(remove);
    }
}
_DrawingList = ordered;

为了实现这一点,我必须覆盖Equals中的GetHashCodeDrawingData

public override bool Equals(object obj)
{
    if (!(obj is DrawingData))
    {
        return base.Equals(obj);
    }
    else
    {
        return this.DrawingName.Equals((obj as DrawingData).DrawingName, StringComparison.OrdinalIgnoreCase);
    }
}

public override int GetHashCode()
{
    return DrawingName.GetHashCode();
}

答案 5 :(得分:0)

假设您要将重复项拆分为单独的列表,则:

首先创建一个用于比较DrawingData个对象的小类:

sealed class Comparer: IComparer<DrawingData>
{
    public int Compare(DrawingData x, DrawingData y)
    {
        // NOTE: Assumes DrawingName, x and y are never null.
        return x.DrawingName.CompareTo(y.DrawingName);
    }
}

然后假设您的示例中有一个填充的列表,List<DrawingData> _DrawingList,拆分重复的项目,以便您有两个单独的列表:

var list1 = new SortedSet<DrawingData>(new Comparer());
var list2 = new SortedSet<DrawingData>(new Comparer());

foreach (var drawing in _DrawingList)
    if (!list1.Add(drawing))
        list2.Add(drawing);

然后根据需要将list1和list2转换为实际列表:

var l1 = list1.ToList();
var l2 = list2.ToList();

答案 6 :(得分:0)

您正在寻找分组,然后进行转置:

string[] data = 
{
    "411000D", 
    "411000D", 
    "411000A",
    "411000A",        
    "411000C",
    "411000C",
    "411000B",
    "411000B"
};

var grouped = data.GroupBy(d => d).OrderBy(g => g.Key).ToList().Transpose();
String.Join(",", grouped.SelectMany(f => f));

结果

  

411000A,411000B,411000C,411000D,411000A,411000B,411000C,411000D

给出以下名为Transpose的扩展方法:

public static IEnumerable<IEnumerable<T>> Transpose<T>(this IEnumerable<IEnumerable<T>> @this) 
{
    var enumerators = @this.Select(t => t.GetEnumerator())
                           .Where(e => e.MoveNext()).ToList();

    while (enumerators.Any()) {
        yield return enumerators.Select(e => e.Current);
        enumerators = enumerators.Where(e => e.MoveNext()).ToList();
    }
}

另一种方法,实施Karel Frajtak的建议:

var result = data.GroupBy(d => d)
                 .SelectMany(g => g.Select((item, indexer) => new { item, indexer}))
                 .OrderBy(a => a.indexer)
                 .ThenBy(a => a.item)
                 .Select(a => a.item);

答案 7 :(得分:0)

虽然不是最优的,但IEnumerable上的递归扩展方法&gt;使用起来可能很有趣,并且在分组之外的一些更一般的情况下很有用:

public static class GroupExtender
{
    public static IEnumerable<T> Mix<T>(this IEnumerable<IEnumerable<T>> groups)
    {
        // enumerate once
        var enumerable = groups as IList<IEnumerable<T>> ?? groups.ToList(); 
        //stop case
        if (!(enumerable.Any(g=>g.Any())))
            return new List<T>();
        // get first elements, iterate over the IEnumerable trimmed of these
        return enumerable
                .SelectMany(g => g.Take(1))
                .Concat(enumerable.Select(g => g.Skip(1)).Mix());
    }
}

获取“有序”项目将是:

var _DrawingListInOrder = 
      _DrawingList.GroupBy(x => x.DrawingName).OrderBy(g => g.Key).Mix();