仅在分层父子关系数据中的父级上的C#LINQ Orderby



我在LINQ中遇到了一个有趣的问题,我不知道如何解决它

我有一个发送对象(List<Send>)的列表,其中发送对象具有以下属性

public class Send
{   
    public string messageName { get; set; }
    public string Port { get; set; }        
    public string Type { get; set; }
}

其中端口可以是PortA, PortB等。类型只能是"receive""transmit",消息名称可以是

0_firstmessage
1_secondmessage
2_thirdmessage

messageName总是在0,1,2….N开头有一个标识符。

我当前的列表中有如下数据。数据中需要注意的几点

  1. 我的数据已经根据端口进行了排序。所以,PortA数据来了首先是PortB
  2. 每个类型为"接收"的消息后面跟着0或N个发送消息组
  3. 每个发送消息总是有一个父接收消息

我的数据:

MESSAGENAME, PORT  , TYPE  
    - 0_message , PortA , receive
       - 1_message , PortA , transmit
       - 3_message , PortA , transmit
       - 7_message , PortA , transmit
    - 8_message , PortA , receive
       - 9_message , PortA , transmit
    - 2_message , PortB , receive
    - 4_message , PortB , receive
       - 5_message , PortB , transmit
       - 6_message , PortB , transmit
    - 10_message, PortB , receive
       - 11_message , PortB , transmit

我的最终输出应该是这样的。

 MESSAGENAME, PORT  , TYPE  
- 0_message , PortA , receive
   - 1_message , PortA , transmit
   - 3_message , PortA , transmit
   - 7_message , PortA , transmit
- 2_message , PortB , receive
- 4_message , PortB , receive
   - 5_message , PortB , transmit
   - 6_message , PortB , transmit
- 8_message , PortA , receive
   - 9_message , PortA , transmit
- 10_message, PortB , receive
   - 11_message , PortB , transmit

我只想基于"接收"类型消息的MESSAGE_NAME进行ORDERBY。孩子"传递"的信息应该保持原样。

我在网上搜索了很多,但我不知道如何编写这个LINQ查询。

这里有一个例子:你可以在这里玩。https://dotnetfiddle.net/DKOOk2

我有一个解决方案,假设您首先收到receive,然后收到transmit类型的消息。

int gid=0;
var results = messages.Select(m => new 
                     {                                 // Rank each message 
                        m.Type.Equals("Receive", StringComparison.InvariantCultureIgnoreCase ) ? ++gid: gid, 
                        message=m 
                     })
    .GroupBy(g=>g.groupid) // Group them on Rank
    .OrderBy(g=>int.Parse(g.First().message.messageName.Split('_')[0]))  // apply Sort
    .SelectMany(c=>c.Select(x=>x.message)) // flatten structure .
    .ToList() ; 

检查工作example

试试下面的代码。

    public class Send : IComparable<Send>
    {
        public string messageName { get; set; }
        public string Port { get; set; }
        public string Type { get; set; }

        public int CompareTo(Send other)
        {
            int results = 0;
            if (this.messageName != other.messageName)
            {
                results = this.messageName.CompareTo(other.messageName);
            }
            else
            {
                if (this.Port != other.Port)
                {
                    results = this.Port.CompareTo(other.Port);
                }
                else
                {
                    results = this.Type.CompareTo(other.Type);
                }
            }
            return results;
        }
    }

我希望这个LINQ能帮助你:

var a = mylist.OrderBy(x => x.MESSAGENAME).Where(y => y.TYPE == "receive")
                      .Concat(mylist.Where(z => z.TYPE!= "receive"));

因此,您将获得IEnumerable,第一个是按消息类型receive发送,第二个是按无序发送。

我还有一个建议给你。您可以添加一个字典,并将您的列表放在key-将是您的发送消息type="receive"的位置,然后您可以简单地按键订购字典。检查此代码:

        List<Send> messages = new List<Send>();
    messages.Add(new Send() {messageName ="0_message" , Port = "PortA", Type="Receive" });
    messages.Add(new Send() {messageName ="1_message" , Port = "PortA", Type="transmit" });
    messages.Add(new Send() {messageName ="3_message" , Port = "PortA", Type="transmit" });
    messages.Add(new Send() {messageName ="7_message" , Port = "PortA", Type="transmit" });
    messages.Add(new Send() {messageName ="8_message" , Port = "PortA", Type="Receive" });
    messages.Add(new Send() {messageName ="9_message" , Port = "PortA", Type="transmit" });
    messages.Add(new Send() {messageName ="2_message" , Port = "PortB", Type="Receive" });
    messages.Add(new Send() {messageName ="4_message" , Port = "PortB", Type="Receive" });
    messages.Add(new Send() {messageName ="5_message" , Port = "PortB", Type="transmit" });
    messages.Add(new Send() {messageName ="6_message" , Port = "PortB", Type="transmit" });
    messages.Add(new Send() {messageName ="10_message" , Port = "PortB", Type="Receive" });
    messages.Add(new Send() {messageName ="11_message" , Port = "PortB", Type="transmit" });

     Dictionary<Send, List<Send>> myDict = new Dictionary<Send, List<Send>>();
        List<Send> mylist2 = new List<Send>();
        Send messagename = new Send();
        int i = 0;

        foreach (Send s in messages)
        {
            if (s.Type == "Receive" || s.Type == "receive")
            {
                if (i != 0)
                {
                    myDict.Add(messagename, mylist2);
                }
                messagename = s;
                mylist2 = new List<Send>();
            }
            else
            {
                mylist2.Add(s);
            }
            if(i== messages.Count()-1)
            {
                myDict.Add(messagename, mylist2);
            }
            i++;
        }
        var q = myDict.OrderBy(x => int.Parse(x.Key.messageName.Split('_')[0]));

如果您愿意,您可以将字典转换回列表:

        List<Send> newlist = new List<Send>();
        foreach (KeyValuePair<Send, List<Send>> k in q)
        {
            newlist.Add(k.Key);
            foreach (Send s in k.Value)
            {
                newlist.Add(s);
            }
        }

最新更新