繁体   English   中英

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

[英]C# LINQ Orderby on parent only in hierarchical parent-child relationship data

我在LINQ中遇到了一个有趣的问题,我不知道如何解决它。 这是我的数据的样子

我有一个Send对象List<Send>List<Send> ),其中Send对象具有以下属性

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

其中Port可以是PortA, PortB等。类型只能是"receive""transmit"而messageName可以是

0_firstmessage
1_secondmessage
2_thirdmessage

messageName始终在开头0,1,2 .... N处有一个标识符。

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

  1. 我的数据已根据Ports排序。 因此,首先是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

我希望ORDERBY基于MESSAGE_NAME仅收到“接收”类型的消息。 孩子“传输”消息应该保持不变。

我在线搜索了很多,但我不知道如何编写这个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,其中第一个按顺序发送按消息类型接收和第二个 - 所有其余发送无序。

我有另一个建议给你。 你可以添加一个字典并将你的列表放在哪里键 - 将是你的发送消息类型=“接收”然后你可以简单地按键排序。 检查此代码:

        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);
            }
        }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM